4-5 Scrapy知识补充
FormRequest
FormRequest类是专门用来处理HTML表单的,同时对隐藏的表单处理也很方便。适合用来完成登录操作。
类原型:class scrapy.http.FormRequest(url[, formdata, ...])其构造参数formdata可以是字典形式,也可以是(key, value)元组形式。代表需提交的表单数据。
return FormRequest(url="http://www.example.com/post/action",formdata={'name': 'John Doe', 'age': '27'},callback=self.after_login)
通常网站通过<inputtype=“hidden”>实现对某些表单字段(如数据或是登录界面中的认证令牌等)的预填充,如前知乎的 _xsrf参数。FormRequest类提供了一个类方法from_response。可以处理这种隐藏的表单。
注意html知识补充:所有需要登陆的表单字段都会在html中的form标签中找到,其中需要输入的在form标签的后辈节点input标签中,然后输出的name和value会在input标签中的name属性和value属性中找到。from_response正式利用此到form标签中的后辈节点寻找input标签然后将其name属性为key和value属性为value收集在一起构造(key, value)作为添加进入formdata的值。

from_response(response[, formname=None, formnumber=0, formdata=None, formxpath=None, clickdata=None])
参数说明:
response:一个包含HTML表单的响应页面。
formname(string):如果不为None,表单中的name属性将会被设定为这个值。
formnumber(int):当响应页面中包含多个HTML表单时,本参数用来指定使用第几个表单,第一个表单数字为0。
formdata(dict):本参数用来填充表单中属性的值。如果其中一个属性的值在响应页面中已经被预填充,但formdata中也指定了这个属性的值,将会把预填充的值覆盖掉。
formxpath(string):如果页面中有多个HTML表单,可以用xpath表达式定位页面中的表单,第一个被匹配的将会被操作。
用from_response方法来实现登录功能,示例如下:
import scrapy
class LoginSpider(scrapy.Spider):
name = 'example.com'
start_urls = ['http://www.example.com/users/login.php']
def parse(self, response):
return scrapy.FormRequest.from_response(response,formdata={'username': 'john', 'password': 'secret'},callback=self.after_login)
def after_login(self, response):
# check login succeed before going on
if "authentication failed" in response.body:
self.logger.error("Login failed")
return
BrowserCooCookieJarkiesMiddleware
源码分析:
首先构造方法中有个 self.jars = defaultdict(CookieJar) 这涉及到defaultdict()的使用。
defaultdict()方法和字典的用法大同小异,最大的区别是当defaultdict()可以接受一个函数或者是类作为参数,然后如果只指定defaultdict的一个键,那么该键的值会被默认的参数(如果是函数则为函数返回值,如果为类则为最基础类)填充。看实例:
from collections import defaultdict
a = defaultdict(list)
b = a['frank']
print(b) 输出结果:
[]
因为defaultdict参数为list,则当指定一个键frank的时候,就会设置该frank的值为一个最基础的列表,即[], 将其值赋给b所以b为[] 甚至可以不指定值给b,直接指定一个键,然后该defaultdict就会变成{'frank': []}
的形式。
from collections import defaultdict
a = defaultdict(list)
a['frank']
print(a) 输出结果:
defaultdict(<class 'list'>, {'frank': []})
回到BrowserCookiesMiddleware类,中构造方法,self.jars = defaultdict(CookieJar) 意思即为类的jars变量创建一个CookieJar对象。 回到CookieJar源码,可以看到该类有一个重要的方法,set_cookie(),该防范出入一个cookie对象作为参数,然后将其添加到CookieJar中。于是根据以上我们可以自己设置自己的 BrowserCooCookieJarkiesMiddleware 来为Request设置cookie
import browsercookie
from scrapy.downloadermiddlewares.cookies import CookiesMiddleware
class MyCookie(CookiesMiddleware):
def __init__(self, debug=False):
super().__init__(debug)
self.load_browser_cookies()
def load_browser_cookies(self):
# 加载Chrome 浏览器中的Cookie
jar = self.jars['chrome']
chrome_cookiejar = browsercookie.chrome()
for cookie in chrome_cookiejar:
jar.set_cookie(cookie)
分析:
- self.load_browser_cookies方法加载浏览器Cookie 。
- 在load_browser_cookies方法中,使用self.jars['chrome']和self.jars['firefox']从默认字典中获得两个CookieJar对象。
- 然后调用browsercookie的chrome和firefox方法,分别获取两个浏览器中的Cookie,将它们填入各自的CookieJar对象中。
Scrapy & bloomfilter
scrapy 自带的去重方案是set()与hashlib.sha1()完成的。源码如下:
def __init__(self, path=None, debug=False):
self.file = None
self.fingerprints = set()
self.logdupes = True
self.debug = debug
self.logger = logging.getLogger(__name__)
if path:
self.file = open(os.path.join(path, 'requests.seen'), 'a+')
self.file.seek(0)
self.fingerprints.update(x.rstrip() for x in self.file)
request_fingerprint方法实现过滤的,将Request指纹添加到set()中。部分源码如下:
def request_fingerprint(request, include_headers=None):
if include_headers:
include_headers = tuple(to_bytes(h.lower())
for h in sorted(include_headers))
cache = _fingerprint_cache.setdefault(request, {})
if include_headers not in cache:
fp = hashlib.sha1()
fp.update(to_bytes(request.method))
fp.update(to_bytes(canonicalize_url(request.url)))
fp.update(request.body or b'')
if include_headers:
for hdr in include_headers:
if hdr in request.headers:
fp.update(hdr)
for v in request.headers.getlist(hdr):
fp.update(v)
cache[include_headers] = fp.hexdigest()
return cache[include_headers]
去重指纹为sha1(method+url+body+header)
4-5 Scrapy知识补充的更多相关文章
- scrapy知识补充--scrapy shell 及Spider
什么是scrapy shell? Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试xpath或css表达是,来查看他们的工作方式,方便爬取页面中的数据 ...
- Redis基础知识补充及持久化、备份介绍(二)--技术流ken
Redis知识补充 在上一篇博客<Redis基础认识及常用命令使用(一)--技术流ken>中已经介绍了redis的一些基础知识,以及常用命令的使用,本篇博客将补充一些基础知识以及redis ...
- CRM中QueryDict和模型表知识补充
CRM中QueryDict和模型表知识补充 1.QueryDict的用法 request.GET的用法:1.在页面上输入:http://127.0.0.1:8000/index/print(reque ...
- Android知识补充(Android学习笔记)
Android知识补充 ●国际化 所谓的国际化,就是指软件在开发时就应该具备支持多种语言和地区的功能,也就是说开发的软件能同时应对不同国家和地区的用户访问,并针对不同国家和地区的用户,提供相应的.符合 ...
- (C/C++学习笔记) 二十四. 知识补充
二十四. 知识补充 ● 子类调用父类构造函数 ※ 为什么子类要调用父类的构造函数? 因为子类继承父类,会继承到父类中的数据,所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程. ...
- SQL语句之 知识补充
SQL语句之 知识补充 一.存储过程 运用SQL语句,写出一个像函数的模块,这就是存储过程. 需求: 编写存储过程,查询所有员工 -- 创建存储过程(必须要指定结束符号) -- 定义结束符号 DELI ...
- Python学习---django知识补充之CBV
Django知识补充之CBV Django: url --> def函数 FBV[function based view] 用函数和URL进行匹配 url --> ...
- 34、Scrapy 知识总结
Scrapy 知识总结 1.安装 pip install wheel pip install https://download.lfd.uci.edu/pythonlibs/q5gtlas ...
- Redis基础知识补充及持久化、备份介绍
Redis知识补充 在上一篇博客<Redis基础认识及常用命令使用(一)–技术流ken>中已经介绍了redis的一些基础知识,以及常用命令的使用,本篇博客将补充一些基础知识以及redis持 ...
随机推荐
- php取整的几种方式,四舍五入,舍去法取整,进一法取整
php取整的几种方式,四舍五入,舍去法取整,进一法取整方式一:round 对浮点数进行四舍五入语法:float round ( float val [, int precision] ) echo r ...
- css去掉button点击后的蓝框
转自:http://www.inbeijing.org/archives/1139 css控制Button 按钮的点击时候出现蓝色边框的问题 添加css属性,这样在点击安按钮的时候就不会有蓝色边框了. ...
- flink 批量梯度下降算法线性回归参数求解(Linear Regression with BGD(batch gradient descent) )
1.线性回归 假设线性函数如下: 假设我们有10个样本x1,y1),(x2,y2).....(x10,y10),求解目标就是根据多个样本求解theta0和theta1的最优值. 什么样的θ最好的呢?最 ...
- 将流数据输出到Mysql中
outputMysqlApp.scala import java.sql.DriverManager import org.apache.spark.SparkConf import org.apac ...
- mac上配置python的安装环境杂记
现在的python的包都是通过pip安装的. 所以非常重要的一步是配置pip的安装源 vi ~/.pip/pip.conf [global] index-url = http://pypi.douba ...
- 1.说一下的 dubbo 的工作原理?注册中心挂了可以继续通信吗?说说一次 rpc 请求的流程?
作者:中华石杉 面试题 说一下的 dubbo 的工作原理?注册中心挂了可以继续通信吗?说说一次 rpc 请求的流程? 面试官心理分析 MQ.ES.Redis.Dubbo,上来先问你一些思考性的问题.原 ...
- redis高并发总结
Redis是单线程的,省去了很多上下文切换线程的时间:(官方答案:因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽.既然单线程容易实现, ...
- springboot项目打成jar包后台运行在linux上
背景:springboot2为为主体搭建的项目,直接打成jar包,上传到linux上面 启动项目:java -jar xx.jar 这样很方便,但是不能关闭窗口,否则项目就停了 后台启动: nohup ...
- chrony服务配置
chrony软件使用说明 chrony简介 chrony是一个开源的自由软件,它能保持系统时钟与时间服务器(ntp)同步,让时间保持精确. 它由两个程序组成:chrongd和chronyc. chro ...
- devops 下测试组织管理面临的挑战及应对
导读 先从引发的5个问题讲起,再简单回顾一下devops 简介和兴起背景 ,再从itest 测试管理团队的视角提出应对办法 DevOps后,测试面临的挑战 敏捷开发必然是迭代开发管理模式 ...