Scrapy笔记11- 模拟登录

有时候爬取网站的时候需要登录,在Scrapy中可以通过模拟登录保存cookie后再去爬取相应的页面。这里我通过登录github然后爬取自己的issue列表来演示下整个原理。

要想实现登录就需要表单提交,先通过浏览器访问github的登录页面https://github.com/login,然后使用浏览器调试工具来得到登录时需要提交什么东西。 我这里使用chrome浏览器的调试工具,F12打开后选择Network,并将Preserve log勾上。我故意输入错误的用户名和密码,得到它提交的form表单参数还有POST提交的UR 去查看html源码会发现表单里面有个隐藏的authenticity_token值,这个是需要先获取然后跟用户名和密码一起提交的。

重写start_requests方法

要使用cookie,第一步得打开它呀,默认scrapy使用CookiesMiddleware中间件,并且打开了。如果你之前禁止过,请设置如下

COOKIES_ENABLES = True

我们先要打开登录页面,获取authenticity_token值,这里我重写了start_requests方法

# 重写了爬虫类的方法, 实现了自定义请求, 运行成功后会调用callback回调函数
def start_requests(self):
return [Request("https://github.com/login",
meta={'cookiejar': 1}, callback=self.post_login)] # FormRequeset
def post_login(self, response):
# 先去拿隐藏的表单参数authenticity_token
authenticity_token = response.xpath(
'//input[@name="authenticity_token"]/@value').extract_first()
logging.info('authenticity_token=' + authenticity_token)
pass

start_requests方法指定了回调函数,用来获取隐藏表单值authenticity_token,同时我们还给Request指定了cookiejar的元数据,用来往回调函数传递cookie标识。

使用FormRequest

Scrapy为我们准备了FormRequest类专门用来进行Form表单提交的

# 为了模拟浏览器,我们定义httpheader
post_headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.8,en;q=0.6",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36",
"Referer": "https://github.com/",
}
# 使用FormRequeset模拟表单提交
def post_login(self, response):
# 先去拿隐藏的表单参数authenticity_token
authenticity_token = response.xpath(
'//input[@name="authenticity_token"]/@value').extract_first()
logging.info('authenticity_token=' + authenticity_token)
# FormRequeset.from_response是Scrapy提供的一个函数, 用于post表单
# 登陆成功后, 会调用after_login回调函数,如果url跟Request页面的一样就省略掉
return [FormRequest.from_response(response,
url='https://github.com/session',
meta={'cookiejar': response.meta['cookiejar']},
headers=self.post_headers, # 注意此处的headers
formdata={
'utf8': '✓',
'login': 'yidao620c',
'password': '******',
'authenticity_token': authenticity_token
},
callback=self.after_login,
dont_filter=True
)] def after_login(self, response):
pass

FormRequest.from_response()方法让你指定提交的url,请求头还有form表单值,注意我们还通过meta传递了cookie标识。它同样有个回调函数,登录成功后调用。下面我们来实现它

def after_login(self, response):
# 登录之后,开始进入我要爬取的私信页面
for url in self.start_urls:
# 因为我们上面定义了Rule,所以只需要简单的生成初始爬取Request即可
yield Request(url, meta={'cookiejar': response.meta['cookiejar']})

重写_requests_to_follow
这里我通过start_urls定义了开始页面,然后生成Request,具体爬取的规则和下一页规则在前面的Rule里定义了。注意这里我继续传递cookiejar,访问初始页面时带上cookie信息。

有个问题刚开始困扰我很久就是这里我定义的spider继承自CrawlSpider,它内部自动去下载匹配的链接,而每次去访问链接的时候并没有自动带上cookie,后来我重写了它的_requests_to_follow()方法解决了这个问题

def _requests_to_follow(self, response):
"""重写加入cookiejar的更新"""
if not isinstance(response, HtmlResponse):
return
seen = set()
for n, rule in enumerate(self._rules):
links = [l for l in rule.link_extractor.extract_links(response) if l not in seen]
if links and rule.process_links:
links = rule.process_links(links)
for link in links:
seen.add(link)
r = Request(url=link.url, callback=self._response_downloaded)
# 下面这句是我重写的
r.meta.update(rule=n, link_text=link.text, cookiejar=response.meta['cookiejar'])
yield rule.process_request(r)

页面处理方法

在规则Rule里面我定义了每个链接的回调函数parse_page,就是最终我们处理每个issue页面提取信息的逻辑

def parse_page(self, response):
"""这个是使用LinkExtractor自动处理链接以及`下一页`"""
logging.info(u'--------------消息分割线-----------------')
logging.info(response.url)
issue_title = response.xpath(
'//span[@class="js-issue-title"]/text()').extract_first()
logging.info(u'issue_title:' + issue_title.encode('utf-8'))

完整源码

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
Topic: 登录爬虫
Desc : 模拟登录https://github.com后将自己的issue全部爬出来
tips:使用chrome调试post表单的时候勾选Preserve log和Disable cache
"""
import logging
import re
import sys
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from scrapy.http import Request, FormRequest, HtmlResponse logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
handlers=[logging.StreamHandler(sys.stdout)]) class GithubSpider(CrawlSpider):
name = "github"
allowed_domains = ["github.com"]
start_urls = [
'https://github.com/issues',
]
rules = (
# 消息列表
Rule(LinkExtractor(allow=('/issues/\d+',),
restrict_xpaths='//ul[starts-with(@class, "table-list")]/li/div[2]/a[2]'),
callback='parse_page'),
# 下一页, If callback is None follow defaults to True, otherwise it defaults to False
Rule(LinkExtractor(restrict_xpaths='//a[@class="next_page"]')),
)
post_headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.8,en;q=0.6",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36",
"Referer": "https://github.com/",
} # 重写了爬虫类的方法, 实现了自定义请求, 运行成功后会调用callback回调函数
def start_requests(self):
return [Request("https://github.com/login",
meta={'cookiejar': 1}, callback=self.post_login)] # FormRequeset
def post_login(self, response):
# 先去拿隐藏的表单参数authenticity_token
authenticity_token = response.xpath(
'//input[@name="authenticity_token"]/@value').extract_first()
logging.info('authenticity_token=' + authenticity_token)
# FormRequeset.from_response是Scrapy提供的一个函数, 用于post表单
# 登陆成功后, 会调用after_login回调函数,如果url跟Request页面的一样就省略掉
return [FormRequest.from_response(response,
url='https://github.com/session',
meta={'cookiejar': response.meta['cookiejar']},
headers=self.post_headers, # 注意此处的headers
formdata={
'utf8': '✓',
'login': 'yidao620c',
'password': '******',
'authenticity_token': authenticity_token
},
callback=self.after_login,
dont_filter=True
)] def after_login(self, response):
for url in self.start_urls:
# 因为我们上面定义了Rule,所以只需要简单的生成初始爬取Request即可
yield Request(url, meta={'cookiejar': response.meta['cookiejar']}) def parse_page(self, response):
"""这个是使用LinkExtractor自动处理链接以及`下一页`"""
logging.info(u'--------------消息分割线-----------------')
logging.info(response.url)
issue_title = response.xpath(
'//span[@class="js-issue-title"]/text()').extract_first()
logging.info(u'issue_title:' + issue_title.encode('utf-8')) def _requests_to_follow(self, response):
"""重写加入cookiejar的更新"""
if not isinstance(response, HtmlResponse):
return
seen = set()
for n, rule in enumerate(self._rules):
links = [l for l in rule.link_extractor.extract_links(response) if l not in seen]
if links and rule.process_links:
links = rule.process_links(links)
for link in links:
seen.add(link)
r = Request(url=link.url, callback=self._response_downloaded)
# 下面这句是我重写的
r.meta.update(rule=n, link_text=link.text, cookiejar=response.meta['cookiejar'])
yield rule.process_request(r)

你可以在GitHub上看到本文的完整项目源码,还有另外一个自动登陆iteye网站的例子。

 

Scrapy笔记11- 模拟登录的更多相关文章

  1. scrapy 通过FormRequest模拟登录再继续

    1.参考 https://doc.scrapy.org/en/latest/topics/spiders.html#scrapy.spiders.Spider.start_requests 自动提交 ...

  2. 笔记-爬虫-模拟登录github

    笔记-模拟登录github 1.      模拟登录github 1.1.    环境准备 安装/升级requests 2.20.0 pip install --upgrade requests pi ...

  3. scrapy基础知识之 scrapy 三种模拟登录策略:

    注意:模拟登陆时,必须保证settings.py里的 COOKIES_ENABLED (Cookies中间件) 处于开启状态 COOKIES_ENABLED = True或 # COOKIES_ENA ...

  4. 通过scrapy,从模拟登录开始爬取知乎的问答数据

    这篇文章将讲解如何爬取知乎上面的问答数据. 首先,我们需要知道,想要爬取知乎上面的数据,第一步肯定是登录,所以我们先介绍一下模拟登录: 先说一下我的思路: 1.首先我们需要控制登录的入口,重写star ...

  5. 潭州课堂25班:Ph201805201 爬虫高级 第五课 sclapy 框架 日志和 settings 配置 模拟登录(课堂笔记)

    当要对一个页面进行多次请求时, 设   dont_filter = True   忽略去重 在 scrapy 框架中模拟登录 创建项目 创建运行文件 设请求头 # -*- coding: utf-8 ...

  6. python爬虫实战(四)--------豆瓣网的模拟登录(模拟登录和验证码的处理----scrapy)

    在利用scrapy框架爬各种网站时,一定会碰到某些网站是需要登录才能获取信息. 这两天也在学习怎么去模拟登录,通过自己码的代码和借鉴别人的项目,调试成功豆瓣的模拟登录,顺便处理了怎么自动化的处理验证码 ...

  7. Scrapy中使用cookie免于验证登录和模拟登录

    Scrapy中使用cookie免于验证登录和模拟登录 引言 python爬虫我认为最困难的问题一个是ip代理,另外一个就是模拟登录了,更操蛋的就是模拟登录了之后还有验证码,真的是不让人省心,不过既然有 ...

  8. 利用scrapy模拟登录知乎

    闲来无事,写一个模拟登录知乎的小demo. 分析网页发现:登录需要的手机号,密码,_xsrf参数,验证码 实现思路: 1.获取验证码 2.获取_xsrf 参数 3.携带参数,请求登录 验证码url : ...

  9. scrapy模拟登录微博

    http://blog.csdn.net/pipisorry/article/details/47008981 这篇文章是介绍使用scrapy模拟登录微博,并爬取微博相关内容.关于登录流程为嘛如此设置 ...

随机推荐

  1. Spring AOP环绕异常影响的报错

    最近遇到一个问题,异常是: java.lang.ClassCastException: org.springframework.http.ResponseEntity cannot be cast t ...

  2. 一步一步的理解javascript的预编译

    首先,我们要知道javascript是单线程.解释性语言.所谓解释性语言,就是翻译一句执行一句.而不是通篇编译成一个文件再去执行. 其实这么说还没有这么直观,读一句执行一句那是到最后的事了.到JS执行 ...

  3. Django的学习——全局的static和templates的使用

    一.问题 首先我们在进行Django框架搭建的时候我们需要建立一个全局的变量,一是为了实现代码的复用,二是为了方便管理,如下图的样式 二.解决 1.修改setting里面的配置文件①templates ...

  4. SpringCloud 别人的主页

    https://www.cnblogs.com/xuwujing/ java(28) springBoot(14) 设计模式(14) springcloud(7) hadoop(7) hive(5) ...

  5. php xdebug的配置、调试、跟踪、调优、分析

    xdebug 的 profiler 是一个强大的工具,它能分析 PHP 代码,探测瓶颈,或者通常意义上来说查看哪部分代码运行缓慢以及可以使用速度提升.Xdebug 2 分析器输出一种兼容 cacheg ...

  6. RFID相关知识总结(超高频UHF)

    RFID标签分类 1.LF(Low frequency) 低频 频段范围: 125 KHz-135KHz(ISO18000-2) 常见应用:该频段特点是具有良好的物体穿透能力.广泛应用于进出管理.门禁 ...

  7. 北理工机器人队RM视觉组ubuntu必备软件安装指南

    基础软件安装 sudo apt update && sudo apt upgrade sudo apt install git curl vim gcc g++ cmake与make ...

  8. 2019 识装java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.识装等公司offer,岗位是Java后端开发,因为发展原因最终选择去了识装,入职一年时间了,也成为了面试官,之 ...

  9. 【开发笔记】- Grails框架定义一个不是数据库字段得属性

    实体类 class Book{ String name String author // myfiled 我不想他在数据库中生成book表的字段 String myfield } 添加声明 class ...

  10. .NetCore之基础

    .NetCore几大特点 这篇文章主要从.NetCore全面开源.依赖注入.包引入.跨平台.应用服务器的特点来入手.大约需要10分钟的阅读时间. 与.Net的区别 在.Net与.NetCore在代码编 ...