Scrapy(五):Response与Request、数据提取、Selector、Pipeline
学习自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的更多相关文章
- Scrapy中response属性以及内容提取
一.属性 url :HTTP响应的url地址,str类型 status:HTTP响应的状态码, int类型 headers :HTTP响应的头部, 类字典类型, 可以调用get或者getlist方法对 ...
- Scrapy 学习笔记(一)数据提取
Scrapy 中常用的数据提取方式有三种:Css 选择器.XPath.正则表达式. Css 选择器 Web 中的 Css 选择器,本来是用于实现在特定 DOM 元素上应用花括号内的样式这样一个功能的. ...
- scrapy 的response 的相关属性
Scrapy中response介绍.属性以及内容提取 解析response parse()方法的参数 response 是start_urls里面的链接爬取后的结果.所以在parse()方法中,我 ...
- Scrapy学习篇(六)之Selector选择器
当我们取得了网页的response之后,最关键的就是如何从繁杂的网页中把我们需要的数据提取出来,python从网页中提取数据的包很多,常用的有下面的几个: BeautifulSoup它基于HTML代码 ...
- scrapy获取当当网中数据
yield 1. 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代 2. yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yiel ...
- iOS五种本地缓存数据方式
iOS五种本地缓存数据方式 iOS本地缓存数据方式有五种:前言 1.直接写文件方式:可以存储的对象有NSString.NSArray.NSDictionary.NSData.NSNumber,数据 ...
- java web 中有效解决中文乱码问题-pageEncoding与charset区别, response和request的setCharacterEncoding 区别
这里先写几个大家容易搞混的编码设置代码: 在jsp代码中的头部往往有这两行代码 pageEncoding是jsp文件本身的编码contentType的charset是指服务器发送给客户端时的内容编码J ...
- python 爬虫与数据可视化--数据提取与存储
一.爬虫的定义.爬虫的分类(通用爬虫.聚焦爬虫).爬虫应用场景.爬虫工作原理(最后会发一个完整爬虫代码) 二.http.https的介绍.url的形式.请求方法.响应状态码 url的形式: 请求头: ...
- Python爬虫框架Scrapy实例(三)数据存储到MongoDB
Python爬虫框架Scrapy实例(三)数据存储到MongoDB任务目标:爬取豆瓣电影top250,将数据存储到MongoDB中. items.py文件复制代码# -*- coding: utf-8 ...
随机推荐
- memcached 小记
Memcached是一个自由开源的,高性能,分布式内存对象缓存系统. Memcached是一种基于内存的key-value存储,用来存储小块的任意数据(字符串.对象).这些数据可以是数据库调用.API ...
- ES_AutoCheck.sh
#!/bin/bash #@es_check #@date 2019/11/26 #@auth tigergao status=`curl -s GET "http://172.16.71. ...
- 线程终止的四种方式,interrupt 方法使用的简单介绍。
一 正常结束. package com.aaa.threaddemo; /* 一 终止线程的四种方式? * 程序运行结束,线程终止. * */ public class ThreadTerminati ...
- springboot 配置springmvc?
package com.aaa.zxf.config; import org.springframework.boot.SpringBootConfiguration; import org.spri ...
- Node.js下载安装与配置(windows)
一.Node.js下载 官网下载地址:下载 | Node.js 中文网 (nodejs.cn) 以Windows64位安装版为例,点击"Windows 安装包(.msi)"右侧的& ...
- Serverless Workflow项目
维基百科对工作流的定义是:对工作流程及其各操作步骤之间业务规则的抽象.概括描述.我们认为工作流的主要职责是: 保证结果一致性,提高容错性要求:对错误重试,捕获,执行回滚或补偿逻辑 为长时间运行的流程维 ...
- AT2402 [ARC072D] Dam
首先我们可以将 \(t_i \times v_i\) 看作一个整体,不妨令 \(x_i = v_i, y_i = t_i \times v_i\) 这样两堆水混合后相当于将两个维度相加,方便了计算. ...
- Spring @Cacheable 缓存不生效的问题
最近在项目中使用了Ehcache缓存,使用方式是用Spring提供的 @Cacheable 注解的方式,这种方式简单.快速.方便,推荐使用. 在使用的过程中,遇到了缓存不生效的情况,经过分析处理,总结 ...
- springboot实现分布式锁(spring integration,redis)
Springboot实现分布式锁(Spring Integration+Redis) 一.在项目的pom.xml中添加相关依赖 1)Spring Integration依赖 <dependenc ...
- Java向mysql中插入时间的方法
ava向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明);部分资料参考网络资源 java向MySQL插入当前时间的四种方式 第一种:将java.util.Date类型的 ...