Python爬虫(十三)使用线程池实现异步爬虫

302 阅读3分钟

爬虫中使用异步实现高性能的数据爬取操作。

 

一:多线程,多进程(不建议)

好处:可以为相关阻塞的操作单独开启线程或者进程,祖泽操作就可以异步执行

坏处:无法没有限制的开启多线程或者多进程

 

二:线程池。进程池(适当的使用):

好处:我们可以降低系统对进程或者线程创建和销毁的一个频率,从而很好的降低系统开销

坏处:线程池中的线程数量是有上限的

 

三:同步爬取的示例

我之前测试过的代码中就有类似的范例。(同步爬取的范例)

爬取贝壳找房中的图片,代码如下:

import time
 import requests
 import random
 
 # 导入线程池模块
 from multiprocessing.dummy import Pool
 # 引入etree模块
 from lxml import etree
 def getImage(url):
     """
     :name 爬取网络图片
     :param url: 图片url
     :return: 无返回值
     """
     # 1:指定url
     # url = "https://resource.guanchao.site/uploads/sowing/welcome-image3.jpg"
     # 2:模拟网络请求链接
     responce = requests.get(url=url)
     # 3:获取响应数据,content获取二进制数据
     content = responce.content
     strs = ''.join(random.sample(['z','y','x','w','v','u','t','s','r','q','p','o','n','m','l','k','j','i','h','g','f','e','d','c','b','a'], 5))

    filename = './img/'+ strs +'.jpg'
    # 4:持久化存储
    with open(filename, 'wb'as fe:
        fe.write(content)
        print('爬取完成'+str(time.time()))

# 加载线上html
# 1:指定url
url = "https://dl.ke.com/ershoufang/"
# 2:UA伪装 将对应的User-Agent封装到一个字典中(浏览器标识去浏览器中用f12查看源代码获取就好了)
headers = {
    "User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36 Edg/98.0.1108.43'
}
# 3:模拟网络请求链接
responce = requests.get(url=url, headers=headers)
# 4:获取响应数据
content = responce.text
# 5 :xpath 解析
tree = etree.HTML(content)
# 6:解析标签,获取数据
html = tree.xpath('//img[@class="lj-lazy"]/@data-original')
for item in html:
    getImage(item)
print(html)

 

上边的代码中,每爬取完成一张图片,我都会输出一个“爬取完成”

程序输出结果如下图所示:

1.png

后边链接的是爬取成功之后的时间戳,我们可以看到,时间戳是从上到下依次增长的。说明这个爬取图片是同步进行的。

 

四:异步爬取的示例

我这里对上边的程序进行一个修改:只需要将for循环调用获取图片的函数那个位置改为有线程池执行即可。

修改完成代码如下:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2022/3/9 19:48
# @Author  : camellia
# @Email   : 805795955@qq.com
# @File    : threadpool.py
# @Software: PyCharm

import time
import requests
import random

# 导入线程池模块
from multiprocessing.dummy import Pool
# 引入etree模块
from lxml import etree
def getImage(url):
    """
    :name 爬取网络图片
    :param url: 图片url
    :return: 无返回值
    """
    # 1:指定url
    # url = "https://resource.guanchao.site/uploads/sowing/welcome-image3.jpg"
    # 2:模拟网络请求链接
    responce = requests.get(url=url)
    # 3:获取响应数据,content获取二进制数据
    content = responce.content

    strs = ''.join(random.sample(['z','y','x','w','v','u','t','s','r','q','p','o','n','m','l','k','j','i','h','g','f','e','d','c','b','a'], 5))

    filename = './img/'+ strs +'.jpg'
    # 4:持久化存储
    with open(filename, 'wb'as fe:
        fe.write(content)
        print('爬取完成'+str(time.time()))

# 加载线上html
# 1:指定url
url = "https://dl.ke.com/ershoufang/"
# 2:UA伪装 将对应的User-Agent封装到一个字典中(浏览器标识去浏览器中用f12查看源代码获取就好了)
headers = {
    "User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36 Edg/98.0.1108.43'
}
# 3:模拟网络请求链接
responce = requests.get(url=url, headers=headers)
# 4:获取响应数据
content = responce.text
# 5 :xpath 解析
tree = etree.HTML(content)
# 6:解析标签,获取数据
html = tree.xpath('//img[@class="lj-lazy"]/@data-original')

# ##########################################################
# 使用线程池爬取数据
# 实例化一个线程池对象
pool = Pool(len(html))
# 传入需要调用的方法 图片列表
pool.map(getImage,html)

# ##########################################################
# 同步爬取数据
# for item in html:
#     getImage(item)
# print(html)

输出结果如下图所示:

2.png

通过上图标红框的位置我们可以看到,其爬取完成的时间相同,这就说明是异步多线程进行爬取的。

 

以上大概就是 python 线程池的 基本使用。

 

有好的建议,请在下方输入你的评论。