Python爬虫——Scrapy框架

news2024/12/26 0:04:10

Scrapy是用python实现的一个为了爬取网站数据,提取结构性数据而编写的应用框架。使用Twisted高效异步网络框架来处理网络通信。

Scrapy架构:

ScrapyEngine:引擎。负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。 此组件相当于爬虫的“大脑”,是 整个爬虫的调度中心。 

Schedule:调度器。接收从引擎发过来的requests,并将他们入队。初始爬取url和后续在页面里爬到的待爬取url放入调度器中,等待被爬取。调度器会自动去掉重复的url。

Downloader:下载器。负责获取页面数据,并提供给引擎,而后提供给spider。

Spider:爬虫。用户编些用于分析response并提取item和额外跟进的url。将额外跟进的url提交给ScrapyEngine,加入到Schedule中。将每个spider负责处理一个特定(或 一些)网站。 

ItemPipeline:负责处理被spider提取出来的item。当页面被爬虫解析所需的数据存入Item后,将被发送到Pipeline,并经过设置好次序

DownloaderMiddlewares:下载中间件。是在引擎和下载器之间的特定钩子(specific hook),处理它们之间的请求(request)和响应(response)。提供了一个简单的机制,通过插入自定义代码来扩展Scrapy功能。通过设置DownloaderMiddlewares来实现爬虫自动更换user-agent,IP等。

SpiderMiddlewares:Spider中间件。是在引擎和Spider之间的特定钩子(specific hook),处理spider的输入(response)和输出(items或requests)。提供了同样简单机制,通过插入自定义代码来扩展Scrapy功能。

数据流:

1.ScrapyEngine打开一个网站,找到处理该网站的Spider,并向该Spider请求第一个(批)要爬取的url(s);

2.ScrapyEngine向调度器请求第一个要爬取的url,并加入到Schedule作为请求以备调度;

3.ScrapyEngine向调度器请求下一个要爬取的url;

4.Schedule返回下一个要爬取的url给ScrapyEngine,ScrapyEngine通过DownloaderMiddlewares将url转发给Downloader;

5.页面下载完毕,Downloader生成一个页面的Response,通过DownloaderMiddlewares发送给ScrapyEngine;

6.ScrapyEngine从Downloader中接收到Response,通过SpiderMiddlewares发送给Spider处理;

7.Spider处理Response并返回提取到的Item以及新的Request给ScrapyEngine;

8.ScrapyEngine将Spider返回的Item交给ItemPipeline,将Spider返回的Request交给Schedule进行从第二步开始的重复操作,直到调度器中没有待处理的Request,ScrapyEngine关闭。

安装scrapy:

1.安装wheel支持:
$ pip install wheel

2.安装scrapy框架:

$ pip install scrapy

3.window下,为了避免windows编译安装twisted依赖,安装下面的二进制包 

$ pip install Twisted-18.4.0-cp35-cp35m-win_amd64.whl

scrapy项目结构:
在某路径下创建scrapy项目: $ scrapy startproject my_project

会产生以下目录和文件:

外部的first目录:整个项目目录

scrapy.cfg:必须有的重要的项目的配置文件

内部的first目录:整个项目的全局目录

item.py:定义Item类,从scrapy.Item继承,里面定义scrapy.Field类

pipelines.py:处理爬取的数据流向。重要的是process_item()方法

first目录下的__init__.py:作为包文件必须有的文件

spiders目录下的__init__.py:也是必须有。在这里可以写爬虫类或爬虫子模块

settings.py:

BOT_NAME  # 爬虫名

ROBOTSTXT_OBEY = True  # 遵守robots协议

USER_AGENT=''  # 指定爬取时使用。一定要更改user-agent,否则访问会报403错误

CONCURRENT_REQUEST = 16  # 默认16个并行

DOWNLOAD_DELAY = 3  # 下载延时

COOKIES_ENABLED = False  # 缺省是启用。一般需要登录时才需要开启cookie

DEFAULT_REQUEST_HEADERS = {}  # 默认请求头,需要时填写

SPIDER_MIDDLEWARES  # 爬虫中间件

DOWNLOADER_MIDDLEWARES  # 下载中间件

'first.middlewares.FirstDownloaderMiddleware': 543  # 543优先级越小越高

'firstscrapy.pipelines.FirstscrapyPipeline': 300  # item交给哪一个管道处理,300优先级越小越高

  

豆瓣书评爬取:

创建爬虫代码模版

命令:scrapy genspider -t basic book douban.com  # book是爬虫名字;douban.com是要爬取的url的域名

模板如下:

# -*- coding: utf-8 -*-
import scrapy


class BookSpider(scrapy.Spider):
    name = 'book'
    allowed_domains = ['douban.com']
    start_urls = ['http://douban.com/']

    def parse(self, response):
        pass

 此时就已经成功创建一个名为‘book’的爬虫,可以通过命令scrapy list查看。

response是服务器端HTTP响应,它是scrapy.http.response.html.HtmlResponse类。由此,修改代码如下 :

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http.response.html import HtmlResponse

class BookSpider(scrapy.Spider):
    name = 'book'  # 爬虫名
    allowed_domains = ['douban.com']  # 域名。爬虫爬取范围
    start_urls = ['https://book.douban.com/tag/%E7%BC%96%E7%A8%8B?start=0&type=T']  # 起始url,从第一页开始爬取

    # 下载器获取WebServer的response,parse就是解析响应response的内容
    def parse(self, response: HtmlResponse):  # 如何解析html;返回一个可迭代对象:利用yiled
        print(type(response))  # scrapy.http.response.html.HtmlResponse
        print(type(response.text))  # str
        print(type(response.body))  # bytes
        print(response.encoding)  # utf-8
        # 将网页内容写入book.html文件内
        with open('/Users/dannihong/Documents/leetcode/scrapy_project/file/book.html', 'w', encoding='utf-8') as f:
            f.write(response.text)
            f.flush()
        except Exception as e:
            print(e)

爬虫获得的内容response对象,可以使用解析库来解析。scrapy包装了lxml,父类TextResponse类也提供了xpath方法和css方法,可以混合使用这两套接口解析HTML。解析html页面内容的示例代码如下:

# -*- coding: utf-8 -*-
from scrapy.http.response.html import HtmlResponse

response = HtmlResponse('file:/Users/dannihong/Documents/leetcode/scrapy_project/file/book.html', encoding='utf-8')
with open('/Users/dannihong/Documents/leetcode/scrapy_project/file/book.html', encoding='utf8') as f:
    response._set_body(f.read().encode())  # _set_body方法将其放入response对象里;需要传入的参数对象是bytes,所以encode()
subjects = response.css('li.subject-item')
for subject in subjects:
    # 提取书籍的网页链接
    href = subject.xpath('.//h2').css('a::attr(href)').extract()
    print('href:', href[0])
    # 使用正则表达式,选取评分是9分以上的书籍
    rate = subject.xpath('.//span[@class="rating_nums"]/text()').re(r'^9.*')
    # rate = subject.css('span.rating_nums::text').re(r'^9\..*')  # 第二种表达方式
    if rate:
        print(rate[0])

item封装数据:

# first/item.py

import scrapy

class Test1ProItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()  # 存放书籍标题的字段
    rate = scrapy.Field()  # 存放书籍评分的字段

# first/first/spiders/book.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http.response.html import HtmlResponse
from ..items import FirstItem  # 从上一层的items.py文件里导入

class BookSpider(scrapy.Spider):
    name = 'book'  # 爬虫名
    allowed_domains = ['douban.com']  # 爬虫爬取范围
    start_urls = ['https://book.douban.com/tag/%E7%BC%96%E7%A8%8B?start=0&type=T']  # 起始url
    custom_settings = {'file_name': '/Users/dannihong/Documents/leetcode/scrapy_project/file/books.json'}  # 一般设置参数
 
    # 下载器获取WebServer的response,parse解析响应的内容;输出items和requests
    def parse(self, response: HtmlResponse):  # 如何解析html;返回一个可迭代对象:利用yiled
        subjects = response.xpath('//li[@class="subject-item"]')
        items = []  # 如果用items=[],最后函数要return items
        for subject in subjects:
            item = FirstItem()  # 声明一个item,相当于一个字典,存放要爬取的数据

            title = subject.xpath('.//h2/a/text()').extract()
            item['title'] = title[0].strip()
            rate = subject.css('span.rating_nums::text').extract()
            item['rate'] = rate[0].strip()

            items.append(item)

        with open('book.json', 'w', encoding='utf8') as f:
            for item in items:
                f.write('{} {}\n'.format(item['title'], item['rate']))

        return items

pipeline处理

将book.py中BookSpider改成生成器,只需要把return items改造成yield item,即由产生一个列表变成yield一个个item。脚手架帮我们创建了一个pipelines.py文件和一个类。 

# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'first.pipelines.FirstPipeline': 300,
}

整数300表示优先级,越小越高。取值范围为0-1000。 

 pipeline.py里常用的方法:

process_item(self, item, spider)  # item表示爬取的一个个数据,spider表示item的爬取者,每一个item处理都得调用。返回一个item对象,或者抛出DropItem异常,被丢弃的item对象将不会被pipeline组件处理;

open_spider(self, spider)  # spider表示被开启的spider,调用一次

close_spider(self, spider)  # spider表示被关闭的spider,调用一次

__init__(self)  # spider创建实例时调用一次

将爬取的数据通过pipeline写入到json文件中,代码如下:

# first/spiders/book.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http.response.html import HtmlResponse
from ..items import Test1ProItem

class BookSpider(scrapy.Spider):
    name = 'book'
    allowed_domains = ['douban.com']
    start_urls = ['https://book.douban.com/tag/%E7%BC%96%E7%A8%8B?start=0&type=T']
    custom_settings = {'file_name': '/Users/dannihong/Documents/leetcode/scrapy_project/file/books.json'}  # spider上自定义配置信息

    def parse(self, response: HtmlResponse):  # 如何解析html;返回一个可迭代对象:利用yiled
        subjects = response.xpath('//li[@class="subject-item"]')
        for subject in subjects:
            item =FirstProItem()
            title = subject.xpath('.//h2/a/text()').extract()
            item['title'] = title[0].strip()
            rate = subject.css('span.rating_nums::text').extract()
            item['rate'] = rate[0].strip()
            yield item  # 返回一个可迭代对象生成器

# first/pipelines.py

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import json
from scrapy import Spider

class Test1ProPipeline(object):
    def __int__(self):
        print('~~~~~~~~~~init~~~~~~~~~~')

    # 每一个item都会执行一次
    def process_item(self, item, spider:Spider):
        print('++++++++++')
        print(item)
        self.file.write('{},\n'.format(json.dumps(dict(item))))
        return item

    # 所有过程在起始的时候执行一次
    def open_spider(self, spider):
        print('==========open spider {}=========='.format(spider))
        # file_name = '/Users/dannihong/Documents/leetcode/scrapy_project/file/books.json'
        file_name = spider.settings['file_name']
        self.file = open(file_name, 'w', encoding='utf-8')
        self.file.write('[\n')

    # 所有过程结束的时候执行一次
    def close_spider(self, spider):
        print('==========close spider {}=========='.format(spider))
        self.file.write(']')
        self.file.close()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/75898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

西部广播电视杂志《西部广播电视》杂志社《西部广播电视》编辑部2022年第21期目录

特稿:乡村振兴战略下的媒体实践《西部广播电视》投稿:cnqikantg126.com 乡村振兴中广播电视角色定位研究 王菾; 1-4 对农宣传中广播电视传播功能研究 周艺培; 5-711 广播电视助力涉农产业发展 胡朗铭; 8-11 省级乡村频道发展的典型个案研…

答疑1209

1、在fmu v2中回传电压值 在comm task 里面有电压读取的任务,pool 电池的电压状态 这是上层会调用hal层,也就是adc.c里面的read函数 主要是fmu v2 里面没有写adc的驱动函数,也就是driver层,这里需要模仿v5上面的驱动来补充一下&a…

[附源码]计算机毕业设计交通事故档案管理系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

Pytest框架批量安装插件解析

1、新建一个工程 使用新的环境变量 1.1.插件文件 新建一个txt的文件,将常用插件放在该文件中,如下图 文件名:requirements.txt 常用插件: pytest pytest-html pytest-xdist pytest-ordering pytest-rerunfailures allure-pyt…

探究菊花文的“密码”(文中转换器源码仅一行代码哦)

菊花文、方框文,看起来很神奇的样子。其实,也就是在字符串中插入了特殊字符,利用特殊字符的显示特性获得的混合显示效果而已。(文中转换器源码仅一行代码哦🤗) (本文获得CSDN质量评分【90】)【学习的细节是欢悦的历程】Python 官网…

Alpine安装Oracle JDK存在的问题

简介 前面我们提到了Alpine使用的不是正统的glibc,对于一些强依赖glibc的系统建议不要使用Alpine,比如使用了Oracle JDK的系统,建议在Alpine换成OpenJDK。 Alpine官方给出了Alpine的三大特征 Small、Simple、Secure,但其实我们知…

【论文阅读】 AdaptivePose: Human Parts as Adaptive Points

DOI:https://doi.org/10.1609/aaai.v36i3.20185 AAAI 2022 Published:2022-06-28 Others阅读/整理:翻译1、翻译2 Intro&Background 多人姿态估计方法 two-stage methods【图a】 这些方法使用绝对关键点位置,定位的…

顺时针打印矩阵

大概题意为: 第一步: 第二步: 第三步: 第四步 : 这样核心就设计好了,接下来设计剩余的东西 设计题目程序 1.题目要求我们返回一个地址,所以我们创造一个一维数组,它的元素个数为行…

华为机试_HJ61 放苹果【简单】【收藏】

目录 描述 输入描述: 输出描述: 解题过程 提交代码 递归方法 动态规划方法 学习代码 递归方法 动态规划方法 收藏点 描述 把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法&#xff…

Postman(七): postman应用实战

Postman(13): postman应用实战 postman应用实战 下面以微信公众平台举例: 第一步、先创建文件夹 第二步、打开postman,创建collections 第三步、设置环境变量,全局变量 设置环境变量;如下图: 设置全局变量&#xf…

银河麒麟V10 + 飞腾CPU编译安装 Qt5.9.9

一、准备工作 1. 下载Qt源码包 这里我们要编译的是Qt5.9.9,下载网址:https://download.qt.io/archive/qt/5.9/5.9.9/single/ 在任意空闲位置新建文件夹,并将源码包放到该目录下。(这里在/home目录下新建名为Qt_Source的文件夹&a…

Unity Animancer插件(二)精确控制

一、通过名称播放动画 前面我们讲的都是直接通过动画片段的引用播放动画,Animancer也提供了直接通过动画名称来播放动画的方法。但这并不是推荐的使用方式,因为通过字符串播放比通过引用播放效率略低,且更难维护。 首先我们需要在角色身上挂…

2022年ACM杰出会员名单公布:23位华人学者入选

12月7日,2022年度ACM杰出会员(Distinguished Member)名单公布! 本次评选设有三个奖项,分别表彰在计算机领域做出的教育贡献、工程贡献和科学贡献。 ACM创立于1947年,目前在全球130多个国家和地区拥有超过…

OceanBase 4.0 解读:降低分布式数据库使用门槛,谈谈我们对小型化的思考

关于作者 赵裕众 OceanBase 资深技术专家,2010 年加入支付宝后从事分布式事务框架的研发,2013 年加入 OceanBase 团队,目前负责存储引擎相关的研发工作。 近年来,随着应用场景多样化和数据量的增长,我们看到分布式数据…

判别分析-书后习题回顾总结

5-2 题目 理论基础 多总体的距离判别 马氏距离:dG2(x)(x−μ)2σ2d^{2}_{G}(x)\frac{(x-\mu)^{2}}{\sigma^{2}}dG2​(x)σ2(x−μ)2​ 取马氏距离最小的那一个,就属于这类。 贝叶斯判别准则 计算qtft(x)q_{t}\times f_{t}(x)qt​ft​(x) ft(x)12πσ…

001:Object-C介绍、创建第一个iOS工程、MVC架构

常见APP基础业务模块: 常见App类型:通信与存储、流媒体、直播技术、图片处理、内容展示、Web、组件化、IM类型、音视频、直播类型、摄影摄像类型、资讯类型、工具、购物类型。 App 展示界面动画:底部TabBar、Navigation、列表、图片ImageVi…

一文囊括Ceph所有利器(工具)

原文链接: 知乎专栏: 一文囊括Ceph所有利器(工具) - 知乎 前言 ceph的工具很多,包括集群管理与运维,还有性能分析等等。 所以本文期望应收尽收所有的工具,也当做自己的一个梳理与总结,当自己需要的时候知道有哪些利器可以使用…

一文搞懂SSL/TLS

SSL/TLS1. 概述2. 协议组成2.1 握手协议(Handshake protocol)2.2 记录协议(Record Protocol)2.3 警报协议(Alert Protocol)3. 密码套件与密钥生成1. 概述 安全套接字层(SSL,Secure …

使用 X2MindSpore 迁移 Pytorch 训练脚本mobileNet支持分布式训练

简介 MindSpore是华为昇腾开发的深度学习框架,旨在提供端边云全场景的AI框架。 Pytorch是由Facebook推出的AI框架。 本教程使用MindStudio中的X2MindSpore功能自动将Pytorch脚本转换为MindSpore脚本的案例。使用的模型是分类任务模型mobileNet,数据集是c…

【自动化测试】Selenium IDE脚本编辑与操作(了解)

之前,我们录制脚本时是录制鼠标和键盘的所有在浏览器的操作,那么脚本会出现多余的步骤,有时候我们需要手动填写脚本或修改脚本,所以我们有必要对selenium IDE脚本编辑与操作有所了解;(采用录制的方式很容易…