python多线程爬虫_Python爬虫程序对比:普通爬虫vs多线程爬虫vs 框架爬虫

前言

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。

基本开发环境

  • Python 3.6

  • Pycharm

目标网页分析网站就选择发表情这个网站吧

108a3a3ca1902885a91797f0279d7396.png

网站是静态网页,所有的数据都保存在 div标签中,爬取的难度不大。

9ebacbb546b5c69a8a93bd596382be63.png

根据标签提取其中的表情包url地址以及标题就可以了。

普通爬虫实现

import requests
import parsel
import re


def change_title(title):
    pattern = re.compile(r"[\/\\\:\*\?\"\\|]")  # '/ \ : * ? "  |'
    new_title = re.sub(pattern, "_", title)  # 替换为下划线
    return new_title


for page in range(0, 201):
    url = f'https://www.fabiaoqing.com/biaoqing/lists/page/{page}.html'
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
    }
    response = requests.get(url=url, headers=headers)
    selector = parsel.Selector(response.text)
    divs = selector.css('.tagbqppdiv')
    for div in divs:
        img_url = div.css('a img::attr(data-original)').get()
        title_ = img_url.split('.')[-1]
        title = div.css('a img::attr(title)').get()
        new_title = change_title(title) + title_
        img_content = requests.get(url=img_url, headers=headers).content
        path = 'img\\' + new_title
        with open(path, mode='wb') as f:
            f.write(img_content)
            print(title)

代码简单的说明:

1、标题的替换,因为有一些图片的标题,其中会含有特殊字符,在创建文件的时候特殊字符是不能命名的,所以需要使用正则把有可能出现的特殊字符替换掉。

def change_title(title):
    pattern = re.compile(r"[\/\\\:\*\?\"\\|]")  # '/ \ : * ? "  |'
    new_title = re.sub(pattern, "_", title)  # 替换为下划线
    return new_title

2、翻页爬取以及模拟浏览器请求网页

# 第一页链接
https://www.fabiaoqing.com/biaoqing/lists/page/0.html
# 第二页链接
https://www.fabiaoqing.com/biaoqing/lists/page/1.htmlfor page in range(0, 201):
for page in range(0, 201):
    url = f'https://www.fabiaoqing.com/biaoqing/lists/page/{page}.html'
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
    }
    response = requests.get(url=url, headers=headers)
    selector = parsel.Selector(response.text)

翻页多点击下一页看一下url地址的变化就可以找到相对应规律了,网站是get请求方式,使用requests请求网页即可,加上headers请求头,伪装浏览器请求,如果不加,网站会识别出你是python爬虫程序请求访问的,不过对于这个网站,其实加不加都差不多的。

3、解析数据提取想要的数据

    divs = selector.css('.tagbqppdiv')
    for div in divs:
        img_url = div.css('a img::attr(data-original)').get()
        title_ = img_url.split('.')[-1]
        title = div.css('a img::attr(title)').get()
        new_title = change_title(title) + title_

这里我们使用的是 parsel 解析库,用的是css选择器 解析的数据。

就是根据标签属性提取相对应的数据内容。

4、保存数据

        img_content = requests.get(url=img_url, headers=headers).content
        path = 'img\\' + new_title
        with open(path, mode='wb') as f:
            f.write(img_content)
            print(title)

请求表情包url地址,返回获取content二进制数据,图片、视频、文件等等都是二进制数据保存的。如果是文字则是text。

path 就是文件保存的路径,因为是二进制数据,所以保存方式是 wb 。

多线程爬虫实现

import requests
import parsel
import re
import concurrent.futures


def get_response(html_url):
    """模拟浏览器请求网址,获得网页源代码"""
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
    }
    response = requests.get(url=html_url, headers=headers)
    return response


def change_title(title):
    """正则匹配特殊字符标题"""
    pattern = re.compile(r"[\/\\\:\*\?\"\\|]")  # '/ \ : * ? "  |'
    new_title = re.sub(pattern, "_", title)  # 替换为下划线
    return new_title


def save(img_url, title):
    """保存表情到本地文件"""
    img_content = get_response(img_url).content
    path = 'img\\' + title
    with open(path, mode='wb') as f:
        f.write(img_content)
        print(title)


def main(html_url):
    """主函数"""
    response = get_response(html_url)
    selector = parsel.Selector(response.text)
    divs = selector.css('.tagbqppdiv')
    for div in divs:
        img_url = div.css('a img::attr(data-original)').get()
        title_ = img_url.split('.')[-1]
        title = div.css('a img::attr(title)').get()
        new_title = change_title(title) + title_
        save(img_url, new_title)


if __name__ == '__main__':
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)
    for page in range(0, 201):
        url = f'https://www.fabiaoqing.com/biaoqing/lists/page/{page}.html'
        executor.submit(main, url)
    executor.shutdown()

简单的代码说明:

其实在前文已经有铺垫了,多线程爬虫就是把每一块都封装成函数,让它每一块代码都有它的作用,然后通过线程模块启动就好。

executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)

最大的线程数

scrapy框架爬虫实现

关于scrapy框架项目的创建这里就不过多讲了,之前文章有详细讲解过,scrapy框架项目的创建,可以点击下方链接查看

简单使用scrapy爬虫框架批量采集网站数据

items.py

import scrapy


class BiaoqingbaoItem(scrapy.Item):
    # define the fields for your item here like:
    img_url = scrapy.Field()
    title = scrapy.Field()

middlewares.py

class BiaoqingbaoDownloaderMiddleware:
    def process_request(self, request, spider):
        # fake = faker.Faker(locale='zh_CN')
        request.headers.update(
            {
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
            }
        )

        return None

pipelines.py

import scrapy
from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline


class DownloadPicturePipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        img_url = item['img_url']
        yield scrapy.Request(img_url, meta={'filename': item['title']})

    def file_path(self, request, response=None, info=None):
        ## 重命名,若不重写这函数,图片名为哈希
        ## 提取url前面名称作为图片名。
        filename = request.meta.get('filename')
        image_guid = filename + '.' + request.url.split('.')[-1]
        return image_guid

setting.py

BOT_NAME = 'biaoqingbao'

SPIDER_MODULES = ['biaoqingbao.spiders']
NEWSPIDER_MODULE = 'biaoqingbao.spiders'

DOWNLOADER_MIDDLEWARES = {
   'biaoqingbao.middlewares.BiaoqingbaoDownloaderMiddleware': 543,
}
ITEM_PIPELINES = {
   'biaoqingbao.pipelines.DownloadPicturePipeline': 300,
}
IMAGES_STORE = './images'

biaoqing.py

import scrapy

from ..items import BiaoqingbaoItem


class BiaoqingSpider(scrapy.Spider):
    name = 'biaoqing'
    allowed_domains = ['fabiaoqing.com']
    start_urls = [f'https://www.fabiaoqing.com/biaoqing/lists/page/{page}.html' for page in range(1, 201)]

    def parse(self, response):
        divs = response.css('#bqb div.ui.segment.imghover div')
        for div in divs:
            img_url = div.css('a img::attr(data-original)').get()
            title = div.css('a img::attr(title)').get()
            yield BiaoqingbaoItem(img_url=img_url, title=title)

简单总结:

三个程序的最大的区别就在于爬取速度的差别,但是如果从写代码的时间上面来计算的话,普通是最简单的,因为对于这样的静态网站根本不需要调试,可以从头写到位,加上空格一共也就是 29行的代码。

如果你是200页的数据量,可以选择多线程是最优选择。爬取速度快,代码不复杂。

如果你是爬取整个网站所有的内容的,建议使用scrapy框架

如果你是爬取十几页的数据,普通爬虫就可以了

如果你是爬取几张图片,建议复制粘贴

综上所述:你更喜欢那种呢?

223dcf819c5bb45614e1dbf1d450a057.gif

点分享

9bd50d2c9374068bdb2c9b41070ad95e.gif

点收藏

529d0d128ed3d54f86c7e306f66c807e.gif

点点赞

259a2e3fc7663fb8091d638f51f1f09c.gif

点在看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值