一、aiohttp與asynic異步爬蟲實例(站長素材)
需求:爬取站長素材圖片,url:http://sc.chinaz.com/tupian/dahaitupian.html
from uuid import uuid4 import aiohttp import asyncio import lxml import requests from bs4 import BeautifulSoup url = "http://sc.chinaz.com/tupian/meinvtupian_%d.html" # 設置請求頭信息 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36' } # 生成soup對象 def get_soup(page_text): # 生成soup對象 soup = BeautifulSoup(page_text, "lxml") return soup # 獲取圖片詳細地址 imgs = [] def get_img_url(page_text): soup = get_soup(page_text) # 獲取所有的div標簽 div_list = soup.select("#container div") for div in div_list: # 獲取到所有圖片的url img_src = div.find("img")["src2"] imgs.append(img_src) return imgs # 回調函數 保存圖片 def url_parse(task): img_data = task.result() filename = f"{uuid4()}.jpg" print("正在下載圖片:", filename) file_path = "./img/"+filename # 寫入文件 with open(file_path, "wb") as fp: fp.write(img_data) # 創建一個特殊函數 async async def get_request(url): # 創建一個aiohttp連接 async with aiohttp.ClientSession() as cs: # 通過異步發送get請求 多任務掛起(await) async with await cs.get(url) as response: # 返回圖片Bytes 字節流 return await response.read() # 爬取圖片地址的url列表 urls = [] # 控制頁面數量,在異步寫入圖片文件,asynic有IO限制,太多IO操作會報錯 for page in range(1, 3): if page == 1: new_url = "http://sc.chinaz.com/tupian/dahaitupian.html" else: new_url = format(url % page) response = requests.get(new_url, headers=headers) response.encoding = "utf-8" page_text = response.text imgs = get_img_url(page_text) urls.append(imgs) # 循環獲取網頁詳情頁 tasks = [] for fir_url in urls: for sec_url in fir_url: # 返回一個協程對象 c = get_request(sec_url) # 通過返回的協程對象進一步封裝成一個任務對象 task = asyncio.ensure_future(c) # 任務回調函數 task.add_done_callback(url_parse) tasks.append(task) # 創建事件循環對象 loop = asyncio.get_event_loop() # 加載任務列表到事件循環,掛起並啟動事件循環 loop.run_until_complete(asyncio.wait(tasks))
二、asynic異步爬取錯誤處理
錯誤原因:
因為asyncio內部用到了select,而select就是系統打開文件數是有限度的,,這個其實是操作系統的限制,linux打開文件的最大數默認是1024,windows默認是509,超過了這個值,程序就開始報錯,
代碼一次性將處理url的函數作為任務扔進了一個超大的List中,這就引起了錯誤。
錯誤處理:
限制並發量,每次爬取不超過509的並發即可。