Python网络爬虫(高性能异步爬虫实例-aiohttp应用)

一、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的并发即可。

 

  

posted @ 2019-08-06 22:30  Amorphous  阅读(1170)  评论(0编辑  收藏  举报