鱼C论坛

 找回密码
 立即注册
查看: 1320|回复: 2

[已解决]异步爬虫

[复制链接]
发表于 2023-7-11 16:20:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
请问各位大佬,这个爬虫怎样改为异步


  1. import requests
  2. import logging
  3. from lxml import html
  4. etree = html.etree
  5. from os import makedirs
  6. from os.path import exists

  7. RESULT = 'doutu'
  8. exists(RESULT) or makedirs(RESULT)

  9. logging.basicConfig(level=logging.INFO,format = '%(asctime)s - %(levelname)s: %(message)s')
  10. index_url = 'https://www.doutub.com/img_lists/new/{}'
  11. header = {
  12.    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
  13.     "Referer":"https://www.doutub.com/"
  14. }
  15. PAGE = 2

  16. #发起请求
  17. def scrape_url(url):
  18.     logging.info('正在爬取{}'.format(url))
  19.     try:
  20.         response = requests.get(url=url,headers=header)
  21.         if response.status_code == 200:
  22.             return response
  23.         logging.error('出现错误,错误代码{}'.format(response.status_code))
  24.     except requests.RequestException:
  25.         logging.error('爬取{}出现错误'.format(url))



  26. #拼接url并发起请求
  27. def scrape_page(page):
  28.     url = index_url.format(page)
  29.     return scrape_url(url).text


  30. #解析表情包url
  31. def parse_url(html):
  32.     href_dic = []
  33.     tree = etree.HTML(html)
  34.     href_list = tree.xpath('//*[@id="__layout"]/div/div/div[2]/div[1]/div[1]/div')
  35.     for href in href_list:
  36.         title = str(href.xpath('./a/@title')[0]).replace('表情包详情','').replace('点击进入','')
  37.         src = href.xpath('./a/img/@data-src')[0]
  38.         href_dic.append({'title':title,'src':src})
  39.     return href_dic

  40. #对图片地址发起请求
  41. def parse_tu(src):
  42.     return scrape_url(src).content


  43. def save_data(title,data):
  44.     title_path = f'{RESULT}/{title}.jpg'
  45.     with open(title_path,'wb') as fp:
  46.         fp.write(data)



  47. def main(page):
  48.     for page in range(1,PAGE+1):
  49.         html = scrape_page(page)
  50.         href_dic = parse_url(html)
  51.         for t in href_dic:
  52.             title = t.get('title')
  53.             src = t.get('src')
  54.             data = parse_tu(src)  
  55.             save_data(title,data)


  56. if __name__ == '__main__':
  57.     main()
复制代码
最佳答案
2023-7-11 16:20:54
要将该爬虫改为异步爬虫,你可以使用aiohttp库实现异步请求。下面是修改后的代码示例:
  1. import asyncio
  2. import aiohttp
  3. import logging
  4. from lxml import html
  5. from os import makedirs
  6. from os.path import exists
  7. RESULT = 'doutu'
  8. exists(RESULT) or makedirs(RESULT)
  9. logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')
  10. index_url = 'https://www.doutub.com/img_lists/new/{}'
  11. header = {
  12.     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
  13.     "Referer": "https://www.doutub.com/"
  14. }
  15. PAGE = 2
  16. async def scrape_url(session, url):
  17.     logging.info('正在爬取{}'.format(url))
  18.     try:
  19.         async with session.get(url=url, headers=header) as response:
  20.             if response.status == 200:
  21.                 return await response.text()
  22.             else:
  23.                 logging.error('出现错误,错误代码{}'.format(response.status))
  24.     except aiohttp.ClientError:
  25.         logging.error('爬取{}出现错误'.format(url))
  26. def scrape_page(session, page):
  27.     url = index_url.format(page)
  28.     return scrape_url(session, url)
  29. def parse_url(html_text):
  30.     href_dic = []
  31.     tree = html.fromstring(html_text)
  32.     href_list = tree.xpath('//*[@id="__layout"]/div/div/div[2]/div[1]/div[1]/div')
  33.     for href in href_list:
  34.         title = str(href.xpath('./a/@title')[0]).replace('表情包详情', '').replace('点击进入', '')
  35.         src = href.xpath('./a/img/@data-src')[0]
  36.         href_dic.append({'title': title, 'src': src})
  37.     return href_dic
  38. async def parse_tu(session, src):
  39.     async with session.get(src) as response:
  40.         if response.status == 200:
  41.             return await response.read()
  42. def save_data(title, data):
  43.     title_path = f'{RESULT}/{title}.jpg'
  44.     with open(title_path, 'wb') as fp:
  45.         fp.write(data)
  46. async def main():
  47.     async with aiohttp.ClientSession() as session:
  48.         tasks = []
  49.         for page in range(1, PAGE + 1):
  50.             html_text = await scrape_page(session, page)
  51.             href_dic = parse_url(html_text)
  52.             for t in href_dic:
  53.                 title = t.get('title')
  54.                 src = t.get('src')
  55.                 tasks.append(asyncio.create_task(parse_tu(session, src)))
  56.                 tasks.append(asyncio.create_task(save_data(title, data)))
  57.         await asyncio.gather(*tasks)
  58. if __name__ == '__main__':
  59.     asyncio.run(main())
复制代码

这里使用asyncio来驱动异步任务,aiohttp库用于发送异步HTTP请求。scrape_url()scrape_page()函数改为异步函数,并使用ClientSession管理HTTP会话。parse_tu()函数也改为异步函数,使用await关键字进行异步等待。main()函数中的请求和保存图片的任务被包装成异步任务列表,最后使用asyncio.gather()来并发执行这些任务。

请注意,由于涉及到IO操作,所以爬虫代码本身的运行速度可能没有明显的提升,但是使用异步可以充分利用并发性能,提高整体效率。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-7-11 16:20:54 | 显示全部楼层    本楼为最佳答案   
要将该爬虫改为异步爬虫,你可以使用aiohttp库实现异步请求。下面是修改后的代码示例:
  1. import asyncio
  2. import aiohttp
  3. import logging
  4. from lxml import html
  5. from os import makedirs
  6. from os.path import exists
  7. RESULT = 'doutu'
  8. exists(RESULT) or makedirs(RESULT)
  9. logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')
  10. index_url = 'https://www.doutub.com/img_lists/new/{}'
  11. header = {
  12.     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
  13.     "Referer": "https://www.doutub.com/"
  14. }
  15. PAGE = 2
  16. async def scrape_url(session, url):
  17.     logging.info('正在爬取{}'.format(url))
  18.     try:
  19.         async with session.get(url=url, headers=header) as response:
  20.             if response.status == 200:
  21.                 return await response.text()
  22.             else:
  23.                 logging.error('出现错误,错误代码{}'.format(response.status))
  24.     except aiohttp.ClientError:
  25.         logging.error('爬取{}出现错误'.format(url))
  26. def scrape_page(session, page):
  27.     url = index_url.format(page)
  28.     return scrape_url(session, url)
  29. def parse_url(html_text):
  30.     href_dic = []
  31.     tree = html.fromstring(html_text)
  32.     href_list = tree.xpath('//*[@id="__layout"]/div/div/div[2]/div[1]/div[1]/div')
  33.     for href in href_list:
  34.         title = str(href.xpath('./a/@title')[0]).replace('表情包详情', '').replace('点击进入', '')
  35.         src = href.xpath('./a/img/@data-src')[0]
  36.         href_dic.append({'title': title, 'src': src})
  37.     return href_dic
  38. async def parse_tu(session, src):
  39.     async with session.get(src) as response:
  40.         if response.status == 200:
  41.             return await response.read()
  42. def save_data(title, data):
  43.     title_path = f'{RESULT}/{title}.jpg'
  44.     with open(title_path, 'wb') as fp:
  45.         fp.write(data)
  46. async def main():
  47.     async with aiohttp.ClientSession() as session:
  48.         tasks = []
  49.         for page in range(1, PAGE + 1):
  50.             html_text = await scrape_page(session, page)
  51.             href_dic = parse_url(html_text)
  52.             for t in href_dic:
  53.                 title = t.get('title')
  54.                 src = t.get('src')
  55.                 tasks.append(asyncio.create_task(parse_tu(session, src)))
  56.                 tasks.append(asyncio.create_task(save_data(title, data)))
  57.         await asyncio.gather(*tasks)
  58. if __name__ == '__main__':
  59.     asyncio.run(main())
复制代码

这里使用asyncio来驱动异步任务,aiohttp库用于发送异步HTTP请求。scrape_url()scrape_page()函数改为异步函数,并使用ClientSession管理HTTP会话。parse_tu()函数也改为异步函数,使用await关键字进行异步等待。main()函数中的请求和保存图片的任务被包装成异步任务列表,最后使用asyncio.gather()来并发执行这些任务。

请注意,由于涉及到IO操作,所以爬虫代码本身的运行速度可能没有明显的提升,但是使用异步可以充分利用并发性能,提高整体效率。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-11 16:22:25 | 显示全部楼层
陶远航 发表于 2023-7-11 16:20
要将该爬虫改为异步爬虫,你可以使用aiohttp库实现异步请求。下面是修改后的代码示例:

好的,感谢感谢
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-23 16:47

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表