学习自Requests and Responses — Scrapy 2.5.0 documentation

Request在Spider中生成,被Downloader执行,之后会得到网页的Response

1、Request

1)构造

scrapy.http.Request(*args,**kw)

2)构造时传入参数

参数 说明 补充
url    
callback 对该URL的返回页面进行处理的回调函数;当该项未指定时,则默认用parse()方法  
method HTTP请求方法,默认'GET' GET、POST、PUT
meta 一些元数据  
body 请求体  
headers 请求头  
cookies    
encoding 请求的编码方式  
priority 请求优先度  
dont_filter 标识该请求不被Scheduler过滤;当我们要经常用到某个request时用到  
errback 异常处理方法;包括网页404错误  
flags    
cb_kwargs

Dict;标识传入参数

return response.follow(url,self.parse_additional_page,cb_kwargs=dict(item=item)
 

补充说明:

1)Request回调函数的作用时机是该request对象对应的response被下载之后,该回调函数将用该Response作为其第一个参数。举例如下:

def parse_page1(self, response):
return scrapy.Request("http://www.example.com/some_page.html",
callback=self.parse_page2) def parse_page2(self, response):
# this would log http://www.example.com/some_page.html
self.logger.info("Visited %s", response.url)

2)一些情况下我们想向回调函数传递参数,可以通过Request.cb_kwargs属性实现。举例如下:

def parse(self,response):
request = scrapy.Request(
url,
callback=self.parse_page,
cb_kwargs=dict(main_url=response.url)
)
# 为回调函数传入额外参数
request.cb_kwars['foo']='bar'
yield request #传入参数可直接写在回调函数的参数中,
#而不用通过response.xxx访问
def parse_pages(self,response,main_url,foo):
yield dict(
main_url=main_url,
ther_url=response.url,
foo=foo
)

3)使用errback处理异常情况

errback是构造Request时定义的一个异常处理函数,当有异常发生时,会调用该方法。它接收Failure作为第一个参数,可以用于追踪超时、DNS错误等。

2、Response

1)属性、方法

属性 类型 说明
url    
status int 响应状态码;默认200
headers Dict 响应头部
body bytes 响应正文
text

str

文本形式的响应正文

response.text = response.body.decode(response.encoding)
encoding  str  响应正文的编码
request  Request 产生该响应的Request对象 
meta   与该Response对应的Request的meta属性;在构造Request对象时,可以将传递给响应处理函函数的信息通过meta参数传入;响应处理函数处理相应时,通过response.meta将信息提取出来
cb_kwargs   传入参数;与Request中的cb_kwargs相对应,通过Response.cb_kwargs提取出来
selector   Selector对象用于在Response中提取数据 
方法 说明
xpath(query) 根据XPath路径表达式提取要素
css(query) 根据CSS语法提取要素
urljoin(url) 用于构造绝对url,当传入的url是一个相对地址时,根据response.url计算出相应的绝对url
follow 返回一个Request实例,接收与Request.__init__方法相同的参数。
follow_all 返回一个Request Iterable,接收与__init__方法相同的参数。

部分方法的详细说明:

follow:

follow(
url, callback, mehod='GET', headers, body,
cookies, meta, encoding='utf-8', priority=0,
dont_filter=False, errback, cb_kwargs, flags
)

返回url对应的Request实例。参数写法与Request对象构建时相同,只是url可以是相对URL,而非绝对URL。

follow_all:

follow_all(
urls, callback, method='GET', headers, body,
cookies, meta, encoding='utf-8', priority=0,
dont_filter=False, errback, cb_kwargs, flags
)

返回Iterable Request,这些Requests与urls相关联。其他方面与follow方法相同。

3、用一个Spider程序来说明Request与Response

import scrapy

class QuotesSpider(scrapy.Spider):
name = "quotes"
def start_requests(self):
urls = [
'http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/2/',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self,response)
page=response.url.split("/")[-2]
filename=f'quotes-{page}.html'
with open(filename,'wb') as f:
f.write(response.body)
self.log(f'Saved file {filename}')

①属性与方法

name:Spider的名字,每个Spider的名字不能相同;

start_requests:必须返回Request()的迭代器(可以是一个Requests List或yield Request())。这些Requests是针对爬虫起始URL进行的;后续的Requests将从这些初始URL中生成。

parse:对之前所有的Requests的Response进行处理,参数中的response保存了页内容并且有一系列方法来处理它。parse方法中一般将爬取到的数据保存为Dict并会自行寻找下一个新的URL(当然这也需要用yield Request(url)进行说明)。

上文的Parse中提取到的网页内容,保存在response.body中,如果要保存为二进制文件,直接保存该项就行了,如果要保存为文本文件,用response.text。

②补充

如果不想写start_requests方法,只需要设置start_urls属性,就可以不用写之前的方法,而对start_urls中的初始URL调用默认的start_requests来对这些URL进行处理。

2、数据提取

最好的提取数据方法是在scrapy shell中进行。

①以http://quotes.toscrape.com/page/1/为例,运行以下指令打开Shell

scrapy shell https://scrapy.org

②之后就可以用response的各项属性和方法进行数据提取了

response.xpath('//title/text()')

提取结果形式为:[ <Selector xpath='xpath表达式' data='提取到的信息' ]

[<Selector xpath='//title/text()' data='Scrapy | A Fast and Powerful Scraping...'>]

如果要提取其中的数据部分,可以用方法extract或getall(提取全部)、get或extract_first(提取首项),当有多个提取项时,extract、getall方法的提取结果是结果List,需要用切片[]的方式提取;也可以用join方法把所有数据连接成为一个str。

③使用正则表达式进行数据提取:re方法

用法:response.xpath('xpath表达式').re(r'正则表达式')

说明:用正则表达式对提取到的要素进行数据再提取,规则与之前正则表达式那一节所说相同,不过re方法,应该是相当于re模块下的search方法,区别在于不需要用group方法,这里re直接返回的结果就是匹配结果,如果正则表达式中有括号,则匹配结果List中保存有原文中符合匹配规则的项

In [8]: response.xpath('//title/text()').re(r'(S\w+)')
Out[8]: ['Scrapy', 'Scraping']

④用yield关键字实现自动爬取

将需要保存的内容,写为Dict形式,用yield标记,即可不停地提取并保存数据:

    def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('small.author::text').get(),
'tags': quote.css('div.tags a.tag::text').getall(),
}

⑤存储爬取数据

scrapy crawl 爬虫名 -o 文件     #追加写
scrapy crawl 爬虫名 -0 文件 #覆盖写 大写字母而非数字

如果要爬取的内容较多,或者更为复杂的存储类型,可以通过在pipelines.py写相应的数据存储语句。

⑥自动翻页功能:response.urlopen(next_page)

该方法只用于静态有规律的URL翻页功能。

next_page = response.urljoin(next_page)

这句话的作用是,将next_page连接到原URL上,构成新的URLnext_page;这样,利用for循环、if语句、yield语句的综合,可以实现不断爬取下一页内容的功能:

#以下代码均写在parse方法中的数据提取语句之后

for i in range(4): #假设提取前3页
next_page=response.urljoin('pw='+str(i))#得到next_page的URL
yield scrapy.Request(next_page,callback=self.parse)

⑦使用参数

方法:在运行爬虫的指定中加入-a后缀

scrapy crawl quotes -0 quotes-humor.json -a tag=humor

这些参数将传入爬虫的__init__方法中,并成为爬虫的默认参数,访问时通过self.tag在__init__中使用。

4、Selector

Selector通过XPath和CSS表达式筛选网页要素

Selector对象是response对象调用XPath与CSS方法后得到的,比如:

scrapy shell https://docs.scrapy.org/en/latest/_static/selectors-sample1.html
In [1]: response.xpath('//title/text()')
Out[1]: [<Selector xpath='//title/text()' data='Example website'>]

如果从Selector中将data提取出来,方法有很多,这里不再多说,见本文第二部分

5、Pipeline

①简介

Item被爬取之后,将被送入Pipeline进行进一步的处理。

每一个Pipeline都是一个class,这个class继承了方法process_item,该方法接收item作为参数,在该方法中对该Item进行一系列处理。

典型的处理方法有:对HTML数据的清洗、检查爬取数据的正确性、检查重复项、存储数据到数据库中。

②类方法

process_item:每个pipeline都必须实现的方法,在其中完成对item的处理

该方法必须返回1)一个Item对象;2)抛出一个DropItem异常;当抛出该异常后,对应的Item将不再会被处理。

open_spider:当Spider开始运行时调用该方法

close_spider:当Spider结束运行时调用该方法

③例子

1)保存提取到了Price的Item,修改其Price,放弃那些不含Price的Item:

from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem
class PricePipeline:
def process_item(self,item,spider):
adapter = ItemAdapter(item)
if adapter.get('price'):
adapter['price'] = adapter['price'] *2
return item
else:
raise DropItem(f'Miss price in {item}')

2)把数据保存到JSON文件中

import json
from itemadapter import ItemAdapter
class JsonWriterPipeline:
def open_spider(self,spider):
self.file=open('items.jl','w')
def close_spider(self,spider):
self.file.close()
def process_item(self,item,spider):
line=json.dumps(dict(item),ensure_ascii=Flase)+'\n'
self.file.write(line)
return item

④激活Pipeline

需要在Setting中设置ITEM_PIPELINES项,才能正确激活Pipeline

ITEM_PIPELINES = {
'myproject.pipelines.PricePipeline': 300,
'myproject.pipelines.JsonWriterPipeline': 800,
}

⑤补充

在没有较多规则限制的情况下,可以在输出时直接输出为json文件,通过-o或-O实现;

Scrapy(五):Response与Request、数据提取、Selector、Pipeline的更多相关文章

  1. Scrapy中response属性以及内容提取

    一.属性 url :HTTP响应的url地址,str类型 status:HTTP响应的状态码, int类型 headers :HTTP响应的头部, 类字典类型, 可以调用get或者getlist方法对 ...

  2. Scrapy 学习笔记(一)数据提取

    Scrapy 中常用的数据提取方式有三种:Css 选择器.XPath.正则表达式. Css 选择器 Web 中的 Css 选择器,本来是用于实现在特定 DOM 元素上应用花括号内的样式这样一个功能的. ...

  3. scrapy 的response 的相关属性

    Scrapy中response介绍.属性以及内容提取   解析response parse()方法的参数 response 是start_urls里面的链接爬取后的结果.所以在parse()方法中,我 ...

  4. Scrapy学习篇(六)之Selector选择器

    当我们取得了网页的response之后,最关键的就是如何从繁杂的网页中把我们需要的数据提取出来,python从网页中提取数据的包很多,常用的有下面的几个: BeautifulSoup它基于HTML代码 ...

  5. scrapy获取当当网中数据

    yield 1. 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代 2. yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yiel ...

  6. iOS五种本地缓存数据方式

    iOS五种本地缓存数据方式   iOS本地缓存数据方式有五种:前言 1.直接写文件方式:可以存储的对象有NSString.NSArray.NSDictionary.NSData.NSNumber,数据 ...

  7. java web 中有效解决中文乱码问题-pageEncoding与charset区别, response和request的setCharacterEncoding 区别

    这里先写几个大家容易搞混的编码设置代码: 在jsp代码中的头部往往有这两行代码 pageEncoding是jsp文件本身的编码contentType的charset是指服务器发送给客户端时的内容编码J ...

  8. python 爬虫与数据可视化--数据提取与存储

    一.爬虫的定义.爬虫的分类(通用爬虫.聚焦爬虫).爬虫应用场景.爬虫工作原理(最后会发一个完整爬虫代码) 二.http.https的介绍.url的形式.请求方法.响应状态码 url的形式: 请求头: ...

  9. Python爬虫框架Scrapy实例(三)数据存储到MongoDB

    Python爬虫框架Scrapy实例(三)数据存储到MongoDB任务目标:爬取豆瓣电影top250,将数据存储到MongoDB中. items.py文件复制代码# -*- coding: utf-8 ...

随机推荐

  1. 计算机网络再次整理————socket[一]

    前言 以前也整理过吧,写了几篇之后,感觉没啥整理的必要了然后就放弃了,最近又想整理一下. 正文 这篇对应的是:https://www.cnblogs.com/aoximin/p/12235333.ht ...

  2. JavaIo流入门篇之字节流基本使用。

    一 基本知识了解(  字节流, 字符流, byte,bit是啥?) /* java中字节流和字符流之前有接触过,但是一直没有深入的学习和了解. 今天带着几个问题,简单的使用字节流的基本操作. 1 什么 ...

  3. 【建议收藏】Redis超详细入门教程大杂烩

    写在前边 Redis入门的整合篇.本篇也算是把2021年redis留下来的坑填上去,重新整合了一翻,点击这里,回顾我的2020与2021~一名大二后台练习生 NoSQL NoSQL(NoSQL = N ...

  4. Webpack 多html入口、devServer、热更新配置

    一.clean-webpack-plugin: 在每次生成dist目录前,先删除本地的dist文件(每次自动删除太麻烦) 1.安装clean-webpack-plugin   npm/cnpm i c ...

  5. java中静态代码块初始化顺序

    (一)java 静态代码块 静态方法区别    一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下, ...

  6. node Cheerio 获取script脚本里的数据

    const cheerio = require('cheerio'); const $ = cheerio.load(html); // your html//如果有多少script脚本标签使用循环来 ...

  7. 二叉树的基本操作(C语言版)

    今天走进数据结构之二叉树 二叉树的基本操作(C 语言版) 1 二叉树的定义 二叉树的图长这样: 二叉树是每个结点最多有两个子树的树结构,常被用于实现二叉查找树和二叉堆.二叉树是链式存储结构,用的是二叉 ...

  8. Note -「Lagrange 插值」学习笔记

    目录 问题引入 思考 Lagrange 插值法 插值过程 代码实现 实际应用 「洛谷 P4781」「模板」拉格朗日插值 「洛谷 P4463」calc 题意简述 数据规模 Solution Step 1 ...

  9. netty系列之:可以自动通知执行结果的Future,有见过吗?

    目录 简介 JDK异步缘起 netty中的Executor Future的困境和netty的实现 总结 简介 在我的心中,JDK有两个经典版本,第一个就是现在大部分公司都在使用的JDK8,这个版本引入 ...

  10. CVE-2021-1732 LPE漏洞分析

    概述 CVE-2021-1732是一个发生在windows内核win32kfull模块的LPE漏洞,并且由于创建窗口时调用win32kfull!xxxCreateWindowEx过程中会进行用户模式回 ...