Scrapy框架之代理和cookie
Cookie 是在 HTTP 协议下,服务器或脚本可以维护客户工作站上信息的一种方式。Cookie 是由 Web 服务器保存在用户浏览器(客户端)上的小文本文件,它可以包含有关用户的信息。无论何时用户链接到服务器,Web 站点都可以访问 Cookie 信息cookie需要个人用户登录网站。
场景需求:获取用户个人主页二级页面的页面数据。
一、Scrapy发起post请求
要登录网站,因此必须发送post请求,如何实现发送post请求?
场景需求:百度翻译中指定词条对应的翻译结果进行获取。
1、方法一:重写start_requests方法来发送post请求
爬虫文件中的爬虫类继承到了Spider父类中的start_requests(self)这个方法,该方法就可以对start_urls列表中的url发起请求。
该方法默认的实现,是对起始的url发起get请求,如果想发起post请求,则需要子类重写该方法。
import scrapy
class PostdemoSpider(scrapy.Spider):
name = 'postDemo'
# allowed_domains = ['www.baidu.com']
start_urls = ['https://fanyi.baidu.com/sug'] # 通过抓包找到post请求地址
def start_requests(self):
"""重写的父类方法:该方法可以对star_urls列表中的元素进行get请求发送"""
for url in self.start_urls:
# Request方法默认发送get请求,配置method参数赋值为'post'
yield scrapy.Request(url=url, callback=self.parse, method='post')
def parse(self, response):
pass
2、方法二:利用FormRequest方法来发送post请求(推荐)
(1)编写爬虫文件postDemo.py
import scrapy
class PostdemoSpider(scrapy.Spider):
name = 'postDemo'
# allowed_domains = ['www.baidu.com']
start_urls = ['https://fanyi.baidu.com/sug'] # 通过抓包找到post请求地址
def start_requests(self):
"""重写的父类方法:该方法可以对star_urls列表中的元素进行get请求发送"""
print("start_requests()被调用")
data = {
'kw': 'dog', # post请求参数
}
for url in self.start_urls:
# FormRequest()可以发送post请求
# formdata表示请求参数对应的字典
yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse)
def parse(self, response):
print(response.text)
(2)编辑settings.py文件
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36' # 伪装请求载体身份
# Obey robots.txt rules
ROBOTSTXT_OBEY = False # 不遵从门户网站robots协议,避免某些信息爬取不到
(3)创建项目、创建应用、执行爬虫
# 创建项目和应用(后面的项目将不再描述)
$ scrapy startproject postPro
$ cd postPro/
$ scrapy genspider postDemo www.baidu.com
# 执行爬虫命令
$ scrapy crawl postDemo --nolog
start_requests()被调用
{"errno":0,"data":[{"k":"dog","v":"n. \u72d7; \u8e69\u811a\u8d27; \u4e11\u5973\u4eba; \u5351\u9119\u5c0f\u4eba; v. \u56f0\u6270; \u8ddf\u8e2a;"},{"k":"dogs","v":"n. \u516c\u72d7( dog\u7684\u540d\u8bcd\u590d\u6570 ); \uff08\u5c24\u7528\u4e8e\u5f62\u5bb9\u8bcd\u540e\uff09\u5bb6\u4f19; [\u673a\u68b0\u5b66]\u5939\u5934; \u4e0d\u53d7\u6b22\u8fce\u7684\u4eba;"},{"k":"doge","v":"n. \u5171\u548c\u56fd\u603b\u7763;"},{"k":"doggy","v":"n. \u5c0f\u72ac\uff0c\u5c0f\u72d7; adj. \u50cf\u72d7\u4e00\u6837\u7684;"},{"k":"doggie","v":"n. \u5c0f\u72d7\uff0c\u72d7\uff0c\u6c6a\u6c6a;"}]}
二、cookie操作
知道post请求后,来实现最开始的场景需求:获取用户个人主页二级页面的页面数据。
新建项目doubanPro,这里没有在管道中处理,简化操作直接在爬虫文件中持久化数据保存在文件中,爬虫文件douban.py如下所示:
import scrapy
class DoubanSpider(scrapy.Spider):
name = 'douban'
allowed_domains = ['www.douban.com']
start_urls = ['https://www.douban.com/accounts/login']
def start_requests(self):
"""重写父类方法"""
# 将请求参数封装到字典
data = {
'source': 'index_nav',
'form_email': '18xxxxxxx0',
'form_password': 'hxxxxxxx'
}
for url in self.start_urls:
yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse)
def parseBySecondPage(self, response):
"""针对个人主页页面数据进行解析操作"""
fp = open('second.html', 'w', encoding='utf-8')
fp.write(response.text)
# 可以对当前用户的个人主页数据进行指定解析操作
# 如果服务器端可以给我们的请求返回一个cookie,第二次使用请求对象发起请求时,cookie就会自动携带到请求中
def parse(self, response):
# 对登录成功后的页面数据进行存储
# 这里没有在管道中处理,简化操作直接保存在文件中
fp = open('main.html', 'w', encoding='utf-8')
fp.write(response.text)
# 获取当前用户的个人主页
url = 'https://www.douban.com/people/186757832/'
yield scrapy.Request(url=url, callback=self.parseBySecondPage)
1、重写父类方法start_requests发起post请求
def start_requests(self):
"""重写父类方法"""
# 将请求参数封装到字典
data = {
'source': 'index_nav',
'form_email': '18xxxxxx0',
'form_password': 'hxxxxxxx'
}
for url in self.start_urls:
yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse)
2、parse和parseBySecondPage方法两次对个人主页发起请求
def parseBySecondPage(self, response):
"""针对个人主页页面数据进行解析操作"""
fp = open('second.html', 'w', encoding='utf-8')
fp.write(response.text)
def parse(self, response):
# 对登录成功后的页面数据进行存储
fp = open('main.html', 'w', encoding='utf-8')
fp.write(response.text)
# 获取当前用户的个人主页
url = 'https://www.douban.com/people/186757832/'
yield scrapy.Request(url=url, callback=self.parseBySecondPage)
如果服务器端可以给我们的请求返回一个cookie,第二次使用请求对象发起请求时,cookie就会自动携带到请求中。
查看mian.html和second.html文件,可以发现两次访问结果相同,说明第二次发请求时携带了cookie。
三、Scrapy代理操作
1、本地ip获取
新建proxyPro工程,通过爬虫在百度搜索ip,获取本地ip地址。
import scrapy
class ProxydemoSpider(scrapy.Spider):
name = 'proxyDemo'
# allowed_domains = ['www.baidu.com/s?wd=ip']
start_urls = ['http://www.baidu.com/s?wd=ip'] # 百度搜索到本地ip
def parse(self, response):
fp = open('proxy.html', 'w', encoding='utf-8')
fp.write(response.text)
爬虫文件编辑好后,修改settings.py文件,执行爬虫:scrapy crawl proxyDemo --nolog;查看proxy.html内容如下所示:
2、下载中间件(Downloader Middlewares)介绍
- 平常情况:
引擎调用start_requests方法,对列表中对应的列表元素进行请求,所有请求成功后,移交给引擎,引擎再将请求提交给调度器,这些请求都放置在调度器队列当中,调度给 下载器,下载器拿到对应的请求去互联网进行下载。 - 代理操作:
调度器将请求给下载器的时候,会穿过下载中间件,下载中间件就可以对请求进行拦截,更换请求对应的ip,换为其他的代理IP。代理IP更换后将请求发给下载器,下载器用修改过ip的请求去互联网去下载。 - 下载中间件的作用:
拦截调度器发给下载器的请求,将请求当中对应的IP进行更换,下载器拿到IP更换后的请求去互联网进行数据的下载。
3、代理操作代码实现
在项目当前的源文件middlewares.py中,可以看到类:ProxyproDownloadMiddleware,这是封装好的下载中间件。其中process_request方法最为重要,负责处理请求。
在全网代理IP网站:http://www.goubanjia.com/,查找一条代理IP地址(39.137.69.10:8434)使用。
(1)自定义下载中间件的类
在middlewares.py中,自定义一个下载中间件的类,在类中实现process_request方法来处理中间件拦截到的请求。
from scrapy import signals
class MyProxy(object):
# 自定义下载中间件
def process_request(self, request, spider):
# 将拦截的请求的请求ip更换
request.meta["proxy"] = "http://39.137.69.10:8434"
注意:
- 自定义类继承object类;
- 重写process_request方法,必须包含父类的self、request、spider这三个参数;
- 用request调出meta这个属性,修改meta中'proxy'这个key对应的value值更换为要修改的代理ip。
(2)修改settings.py使用自定义的中间件
使用下载中间件,需要在配置文件中开启下载中间件。
# Enable or disable downloader middlewares
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = { # 开启下载中间件
# 'proxyPro.middlewares.ProxyproDownloaderMiddleware': 543,
# 自定义下载中间件
'proxyPro.middlewares.MyProxy': 543, # 543为优先级级别
}
(3)执行爬虫查看百度搜索得到的ip地址
$ scrapy crawl proxyDemo
查看获得的页面信息: