# 3.6. 下载中间件和模拟登陆
# 目标
- 掌握常见的下载中间件的编写方式
- 掌握模拟登陆的思路
- 掌握scrapy中模拟登陆的三种方式
# 1. scrapy中下载中间件的使用
使用方法:
编写一个
Downloader Middlewares
和我们编写一个pipeline一样,定义一个类,然后在setting中开启Downloader Middlewares
默认的方法:process_request(self, request, spider):
- 当每个request通过下载中间件时,该方法被调用。
- 返回None值:继续请求
- 返回Response对象:不在请求,把response返回给引擎
- 返回Request对象:把request对象交给调度器进行后续的请求
process_response(self, request, response, spider):
- 当下载器完成http请求,传递响应给引擎的时候调用 - 返回Resposne:交给process_response来处理 - 返回Request对象:交给调取器继续请求
1
2
3
定义实现随机User-Agent的下载中间件
class UserAgentMiddleware(object): def process_request(self,request,spider): agent = random.choice(agents) request.headers['User-Agent'] = agent
1
2
3
4定义实现随机使用代理的下载中间件
class ProxyMiddleware(object): def process_request(self,request,spider): proxy = random.choice(proxies) request.meta['proxy'] = proxy
1
2
3
4User-Agent池在这里
USER_AGENTS = [ "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)", "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)", "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)", "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0", "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5" ]
1
# 2. 使用scrapy进行模拟登陆
# 2.1 回顾之前的模拟登陆的方法
- requests是如何模拟登陆的?
- 直接携带cookies请求页面
- 找接口发送post请求存储cookie
- selenium是如何模拟登陆的?
- 找到对应的input标签,输入文字点击登录
scrapy来说,有两个方法模拟登陆:
1、直接携带cookie
2、找到发送post请求的url地址,带上信息,发送请求
2
# 2.2 scrapy携带cookie进行模拟登陆
携带cookie进行模拟登陆应用场景:
- cookie过期时间很长,常见于一些不规范的网站
- 能在cookie过期之前把搜有的数据拿到
- 配合其他程序使用,比如其使用selenium把登陆之后的cookie获取到保存到本地,scrapy发送请求之前先读取本地cookie
scrapy的start_requests方法的学习
scrapy中start_url是通过start_requests来进行处理的,其实现代码如下
def start_requests(self): cls = self.__class__ if method_is_overridden(cls, Spider, 'make_requests_from_url'): warnings.warn( "Spider.make_requests_from_url method is deprecated; it " "won't be called in future Scrapy releases. Please " "override Spider.start_requests method instead (see %s.%s)." % ( cls.__module__, cls.__name__ ), ) for url in self.start_urls: yield self.make_requests_from_url(url) else: for url in self.start_urls: yield Request(url, dont_filter=True)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15所以对应的,如果start_url地址中的url是需要登录后才能访问的url地址,则需要重写
start_request
方法并在其中手动添加上cookie实现携带cookie登录人人网
注意:scrapy中cookie不能够放在headers中,在构造请求的时候有专门的cookies参数,能够接受字典形式的coookie
import scrapy
import re
class RenrenSpider(scrapy.Spider):
name = 'renren'
allowed_domains = ['renren.com']
start_urls = ['http://www.renren.com/941954027/profile']
def start_requests(self):
cookie_str = "cookie_str"
cookie_dict = {i.split("=")[0]:i.split("=")[1] for i in cookie_str.split("; ")}
yield scrapy.Request(
self.start_urls[0],
callback=self.parse,
cookies=cookie_dict,
# headers={"Cookie":cookie_str}
)
def parse(self, response):
ret = re.findall("新用户287",response.text)
print(ret)
yield scrapy.Request(
"http://www.renren.com/941954027/profile?v=info_timeline",
callback=self.parse_detail
)
def parse_detail(self,response):
ret = re.findall("新用户287",response.text)
print(ret)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
在settings中开启cookie_debug
在settings.py中通过设置
COOKIES_DEBUG=TRUE
能够在终端看到cookie的传递传递过程
# 2.3 scrapy发送post请求
scrapy中发送post请求的方法 通过
scrapy.FormRequest
能够发送post请求,同时需要添加fromdata
参数作为请求体,以及callback
yield scrapy.FormRequest( "https://github.com/session", formdata={ "authenticity_token":authenticity_token, "utf8":utf8, "commit":commit, "login":"noobpythoner", "password":"zhoudawei123" }, callback=self.parse_login )
1
2
3
4
5
6
7
8
9
10
11使用scrapy模拟登陆github
思路分析
找到post的url地址
点击登录按钮进行抓包,然后定位url地址为
https://github.com/session
找到请求体的规律
分析post请求的请求体,其中包含的参数均在前一次的响应中
验证是否登录成功
通过请求个人主页,观察是否包含用户名
代码实现如下:
#spider/github.py # -*- coding: utf-8 -*- import scrapy import re class GithubSpider(scrapy.Spider): name = 'github' allowed_domains = ['github.com'] start_urls = ['https://github.com/login'] def parse(self, response): authenticity_token = response.xpath("//input[@name='authenticity_token']/@value").extract_first() utf8 = response.xpath("//input[@name='utf8']/@value").extract_first() commit = response.xpath("//input[@name='commit']/@value").extract_first() yield scrapy.FormRequest( "https://github.com/session", formdata={ "authenticity_token":authenticity_token, "utf8":utf8, "commit":commit, "login":"noobpythoner", "password":"***" }, callback=self.parse_login ) def parse_login(self,response): ret = re.findall("noobpythoner",response.text,re.I) print(ret)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 2.3 scrapy进行表单提交
方法介绍
scrapy中具有一个方法:
scrapy.Formrequest.from_response
能够自动的从响应中寻找form表单,然后把formdata中的数据提交到action对应的url地址中使用实例如下
def parse(self, response): yield scrapy.FormRequest.from_response( response,#自动的从中寻找action对应的url地址 formdata={ "login":"noobpythoner", "password":"***" }, callback = self.parse_login )
1
2
3
4
5
6
7
8
9使用
scrapy.Formrequest.from_response
进行模拟登陆github
# 小结
- 本小结重点
- 掌握下载中间件的使用方式
- 了解中间件中的方法和返回值
- 掌握scrapy携带cookie进行登录的方法
- 掌握scrapy发送post请求的方法
- 掌握scrapy进行表单提交的方法