【爬虫】3.Scrapy框架以及Request/Response

scrapy框架

在这里插入图片描述

组件描述类型
Scrapy Engine引擎,负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等内部组件
Scheduler调度器:,它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。内部组件
Downloader下载器:负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理内部组件
Spider爬虫:它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器),用户实现
Item Pipeline管道:它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方.可选组件
Downloader Middlewares下载中间件:你可以当作是一个可以自定义扩展下载功能的组件,负责对resquest和response对象处理。可选组件
Spider MiddlewaresSpider中间件:你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests )可选组件

流程:

  • 当SPIDER要爬取某URL地址的页面时,需使用该URL构造一 个Request对象,提交给ENGINE。
  • Request对象随后进入SCHEDULER按某种算法进行排队,之 后的某个时刻SCHEDULER将其出队,送往DOWNLOADER。
  • DOWNLOADER根据Request对象中的URL地址发送一次HTTP 请求到网站服务器,之后用服务器返回的HTTP响应构造出一个 Response对象,其中包含页面的HTML文本。
  • Response对象最终会被递送给SPIDER的页面解析函数(构造 Request对象时指定)进行处理,页面解析函数从页面中提取数据,封装成Item后提交给ENGINE,Item之后被送往ITEM PIPELINES进行处理,最终可能由EXPORTER以某种数据格式写入文件(csv,json);另一方面,页面解析函数还从页面中提取链接(URL),构造出新的Request对象提交给ENGINE。

Resquest/Response对象

Resquest

Request对象用来描述一个HTTP请求,下面是其构造器方法的参数列表:

Request(url[,callback,method='GET',headers,body,cookies,meta,encoding='utf8',priority=0,dont_filter=False,errback])
参数描述
url(必须)请求页面的url地址,bytes或str类型, 如’http://www.python.org/doc’。
callback页面解析函数,Callable类型,Request对象请求的页面下载完成后,由该参数指定的页面解析函数被调用。如果未传递该参数,默认调用Spider的parse方法
methodHTTP请求的方法,默认为’GET’
headersHTTP请求的头部字典,dict类型,例如{‘Accept’: ‘text/html’,‘User-Agent’:Mozilla/5.0’}。如果其中某项的值为None,就表示不发送该项HTTP头部,例如{‘Cookie’: None},禁止发送Cookie
bodyHTTP请求的正文,bytes或str类型
cookiesCookie信息字典,dict类型,例如{‘currency’:‘USD’, ‘country’:‘UY’}。
metaRequest的元数据字典,dict类型,用于给框架中其他组件传递信息,比如中间件Item Pipeline。其他组件可以使用Request对象的meta属性访问该元数据字典(request.meta),也用于给响应处理函数传递信息,详见Response的meta属性
encodingurl和body参数的编码默认为’utf-8’。如果传入的url或 body参数是str类型,就使用该参数进行编码。
priority请求的优先级默认值为0,优先级高的请求优先下载。
dont_filter默认情况下(dont_filter=False),对同一个url地址多次提交下载请求,后面的请求会被去重过滤器过滤(避免重复下载)。如果将该参数置为True,可以使请求避免被过滤,强制下载。例如,在多次爬取一个内容随时间而变化的页面时(每次使用相同的url),可以将该参数置为True。
errback请求出现异常或者出现HTTP错误时(如404页面不存在)的回调函数。

Response

Response对象用来描述一个HTTP响应,Response只是一个基类,根据响应内容的不同有TextResponse,HtmlResponse,XmlResponse,我们通常爬取的网页,其内容是HTML文本,创建的便是HtmlResponse对象,HtmlResponse对象有很多属性,但最常用的是以下的3个方法:

  • xpath(query)
  • css(query)
  • urljoin(url)
    前两个方法用于提取数据,后一个方法用于构造绝对url。

spider开发流程

Scrapy框架提出以下问题让用户在Spider子类中作答:
● 爬虫从哪个或哪些页面开始爬取?
● 对于一个已下载的页面,提取其中的哪些数据?
● 爬取完当前页面后,接下来爬取哪个或哪些页面?
上面问题的答案包含了一个爬虫最重要的逻辑,回答了这些问题,一个爬虫也就开发出来了。
以上一节的代码为例:

import scrapy


class BooksSpider(scrapy.Spider):
    # 定义唯一标识
    name = "books"
    # 爬虫爬取起点网页
    start_urls = [
        'http://books.toscrape.com/',
    ]

    def parse(self, response):
        #	提取数据
        #	每一本书的信息在<article class="product_pod">中
        #	css()方法找到所有这样的article元素,并依次迭代
        for book in response.css('article.product_pod'):
            #   选择器可以通过命令行工具就行调试
            #	书名信息在article>h3>a元素的title属性里
            #	例 如:<a title="A Light in the Attic">A Light in the...</a>
            #	书价信息在<p	class="price_color">的TEXT中。
            #	例如:<p class="price_color">£51.77</p>
            yield {
                # xpath 语法 @ATTR 为选中为名ATTR的属性节点
                'name': book.xpath('h3/a/@title').get(),
                'price': book.css('p.price_color::text').get(),
            }
        # 检查分页
        # 提取下一页的链接
        #例如:<li class="next"><a href="catalogue/page2.html">next</a></li>
        next_url = response.css('ul.pager li.next a::attr(href)').extract_first()
        if next_url:
            next_url = response.urljoin(next_url)
            # 构造新的 Request 对象
            yield scrapy.Request(next_url, callback=self.parse)

实现一个爬虫的主要步骤有4个。

  • 继承scrapy.Spider。
  • 为Spider取名。
  • 设定起始爬取点。
  • 实现页面解析函数

继承scrapy.Spider

import scrapy
class BooksSpider(scrapy.Spider):
	...

为Spider取名

name = "books"

一个scrapy项目中可以有多个Spider,类属性name就是每一个Spider的唯一标识。在scrapy crawl命令中就使用了该标志,表示启动哪一个Spider。

设置爬虫起点

start_urls = ['http://books.toscrape.com/',]

这是一个列表,可以放置所有起始网页。scrapy会调用Spider的start_requests方法,实现对起始网页的下载请求。我们也可以重构该方法。

def start_requests(self):
	yield scrapy.Request('http://books.toscrape.com/',
						  callback=self.parse_book,
						  headers={'UserAgent':	'Mozilla/5.0'},
						  dont_filter=True)

解析界面

页面解析函数也就是构造Request对象时通过callback参数指定的回调函数(或默认的parse方法)。页面解析函数是实现Spider中最核心的部分,它需要完成以下两项工作:
● 使用选择器提取页面中的数据,将数据封装后(Item或字典) 提交给Scrapy引擎。
● 使用选择器或LinkExtractor提取页面中的链接,用其构造新的 Request对象并提交给Scrapy引擎(下载链接页面)。
一个页面中可能包含多项数据以及多个链接,因此页面解析函数被要求返回一个可迭代对象(通常被实现成一个生成器函数),每次迭代返回一项数据(Item或字典)或一个Request对象。

简单利用,刷CSDN博客阅读量

需求很简单,抓取博客的链接。起始界面为https://blog.csdn.net/fxflyflyfly

import scrapy


class BooksSpider(scrapy.Spider):
    name = "csdn"
    start_urls = ['https://blog.csdn.net/fxflyflyfly/article/list/1?',
                  'https://blog.csdn.net/fxflyflyfly/article/list/2?']

    def parse(self, response):
        for book in response.css('div.article-item-box'):
            yield {
                'name':book.xpath('//a/text()').get(),
                'type':book.css('span.article-type::text').get(),
                'list':book.css('h4 a::attr(href)').get(),
            }

因为目前的博客数量不多,不用分页处理,直接设置两个起始网页,抓取博客标题,类型和url。运行上述代码,并将数据保存(出现了中文乱码的问题,暂时还没有解决)。之后处理

接下来就是利用这些链接刷博客量。

import webbrowser as web
import os
import time

url = []
with open('C:/Users/fx/example/example/spiders/csdn.csv', encoding='utf-8') as lines:
    next(lines)
    for line in lines:
        url.append(line.split(',')[-1].strip())

for j in range(10):
    for i in url:
        web.open(i, 0, autoraise=False)
        time.sleep(2)
        os.system('taskkill /F /IM MicrosoftEdgeCP.exe')
    time.sleep(30)

上述通过打开电脑默认浏览器浏览指定url,通过直接杀死进程的方式关闭网页。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,这是一个比较完整的爬虫项目,需要考虑很多方面。下面是一个大致的思路: 1. 创建一个 Scrapy 项目,定义好 Item 和 Spider。 2. 在 Spider 中定义初始页面和翻页的规则。首先要爬取的是 https://lishi.tianqi.com/beijing/index.html 这个页面,然后在该页面中找到“选择月份”的链接,用它来构造翻页规则,例如: ```python start_urls = ["https://lishi.tianqi.com/beijing/index.html"] def parse(self, response): # 获取“选择月份”的链接 month_links = response.css('.tqtongji2 .tqmonth a::attr(href)').getall() for link in month_links: yield scrapy.Request(url=link, callback=self.parse_month_page) ``` 在 `parse_month_page` 方法中,可以解析每个月份的页面,并把数据存入 CSV 文件和 MySQL 数据库中。 3. 在 Item 中定义需要爬取的数据字段,例如日期、温度、气压、风力等: ```python class WeatherItem(scrapy.Item): date = scrapy.Field() temperature = scrapy.Field() pressure = scrapy.Field() wind = scrapy.Field() ``` 4. 在 Spider 中解析每个月份的页面,获取数据并存入 CSV 文件和 MySQL 数据库中。首先要找到每个月份页面中的天气数据表格,然后循环解析每一行数据: ```python def parse_month_page(self, response): # 找到天气数据表格 table = response.css('.tqtongji1 table')[1] rows = table.css('tr') for row in rows[1:]: # 解析每一行数据 item = WeatherItem() item['date'] = row.css('td:nth-child(1)::text').get() item['temperature'] = row.css('td:nth-child(2)::text').get() item['pressure'] = row.css('td:nth-child(3)::text').get() item['wind'] = row.css('td:nth-child(4)::text').get() yield item ``` 5. 在 Spider 中定义数据存储管道,将数据存入 CSV 文件和 MySQL 数据库中: ```python class WeatherPipeline: def open_spider(self, spider): self.file = open('weather.csv', 'w', encoding='utf-8', newline='') self.writer = csv.writer(self.file) self.writer.writerow(['日期', '温度', '气压', '风力']) self.conn = pymysql.connect(host='localhost', user='root', password='123456', db='test', charset='utf8') self.cursor = self.conn.cursor() def close_spider(self, spider): self.file.close() self.conn.close() def process_item(self, item, spider): # 写入 CSV 文件 self.writer.writerow([item['date'], item['temperature'], item['pressure'], item['wind']]) # 存入 MySQL 数据库 sql = "INSERT INTO weather(date, temperature, pressure, wind) VALUES (%s, %s, %s, %s)" values = (item['date'], item['temperature'], item['pressure'], item['wind']) self.cursor.execute(sql, values) self.conn.commit() return item ``` 6. 在 Spider 中定义翻页的规则。根据“选择月份”的链接构造出每个月份页面的 URL,例如 https://lishi.tianqi.com/beijing/202208.html,https://lishi.tianqi.com/beijing/202209.html,https://lishi.tianqi.com/beijing/202210.html 等等,可以使用 `scrapy.Request` 方法来构造请求: ```python def parse(self, response): # 获取“选择月份”的链接 month_links = response.css('.tqtongji2 .tqmonth a::attr(href)').getall() for link in month_links: # 构造每个月份页面的 URL url = response.urljoin(link.replace('.html', '')) for i in range(1, 32): # 构造每一天的 URL day_url = url + f'{i:02d}.html' yield scrapy.Request(url=day_url, callback=self.parse_day_page) ``` 在 `parse_day_page` 方法中,可以解析每一天的页面,并把数据存入 CSV 文件和 MySQL 数据库中。 以上就是一个大致的思路,具体的实现细节还需要根据实际情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值