scrapy爬虫之模拟登录豆瓣

简介

在之前的博文python爬虫之模拟登陆csdn使用urllib、urllib2、cookielib及BeautifulSoup等基本模块实现了csdn的模拟登录,本文通过scrapy模拟登录豆瓣,来深入了解下scrapy。

豆瓣登录需要输入图片验证码,我们的程序暂时不支持自动识别验证码,需要将图片下载到本地并打开以进行人工识别输入到程序中。

分析豆瓣登录

1.分析豆瓣登录页的样式https://accounts.douban.com/login
豆瓣登录页

从上图可以看出:
(1).表单的action地址为

https://accounts.douban.com/login

(2).验证码图片的地址为

https://www.douban.com/misc/captcha?id=TqRY2JmFX9EYfLANfLPOURJ5:en&size=s

(3).captcha-id值

<input name="captcha-id" value="TqRY2JmFX9EYfLANfLPOURJ5:en" type="hidden">

2.分析豆瓣登录页的form表单登录
通过登录页我们登录一次,查看post的数据
登录
因此我们需要通过scrapy提取以下来填充表单:
captcha-id:图片验证码id
captcha-solution:图片验证码,我们通过查看图片手动输入验证码

其他如form_email等固定信息我们可以提前填入表单。

实现

1.建立爬虫

source activate scrapy
#使用PIL打开图片验证码,以便我们识别手动输入
conda install PIL
pip install Pillow
scrapy genspider douban_login douban.com

2.编写爬虫

vim douban/spider/douban_login.py
# -*- coding: utf-8 -*-
import scrapy
import urllib
from PIL import Image


class DoubanLoginSpider(scrapy.Spider):
    name = 'douban_login'
    allowed_domains = ['douban.com']
#    start_urls = ['http://www.douban.com/']
    headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0"}

    def start_requests(self):
        '''
        重写start_requests,请求登录页面
        '''
        return [scrapy.FormRequest("https://accounts.douban.com/login", headers=self.headers, meta={"cookiejar":1}, callback=self.parse_before_login)]

    def parse_before_login(self, response):
        '''
        登录表单填充,查看验证码
        '''
        print("登录前表单填充")
        captcha_id = response.xpath('//input[@name="captcha-id"]/@value').extract_first()
        captcha_image_url = response.xpath('//img[@id="captcha_image"]/@src').extract_first()
        if captcha_image_url is None:
                print("登录时无验证码")
                formdata = {
                                "source": "index_nav",
                                "form_email": "[email protected]",
                                #请填写你的密码
                                "form_password": "********",
                        }
        else:
                print("登录时有验证码")
                save_image_path = "/home/yanggd/python/scrapy/douban/douban/spiders/captcha.jpeg"
                #将图片验证码下载到本地
                urllib.urlretrieve(captcha_image_url, save_image_path)
                #打开图片,以便我们识别图中验证码
                try:
                        im = Image.open('captcha.jpeg')
                        im.show()
                except:
                        pass
        #手动输入验证码
                captcha_solution = raw_input('根据打开的图片输入验证码:')
                formdata = {
                                "source": "None",
                                "redir": "https://www.douban.com",
                                "form_email": "[email protected]",
                                #此处请填写密码
                                "form_password": "********",
                                "captcha-solution": captcha_solution,
                                "captcha-id": captcha_id,
                                "login": "登录",
                        }


        print("登录中")
        #提交表单
        return scrapy.FormRequest.from_response(response, meta={"cookiejar":response.meta["cookiejar"]}, headers=self.headers, formdata=formdata, callback=self.parse_after_login)
    def parse_after_login(self, response):
        '''
        验证登录是否成功
        '''
        account = response.xpath('//a[@class="bn-more"]/span/text()').extract_first()
        if account is None:
                print("登录失败")
        else:
                print(u"登录成功,当前账户为 %s" %account)

注意:请将代码中的登陆账号密码改成你自己的。
3.运行爬虫

扫描二维码关注公众号,回复: 879023 查看本文章
#运行爬虫
scrapy crawl douban_login

运行过程中,爬虫会保存图片到本地并自动打开图片,方便我们识别验证码并手动输入:
识别并输入验证码

爬虫运行的调试信息主要如下:

#打印部分输出日志,主要是供我们调试使用
2017-12-28 14:15:31 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2017-12-28 14:15:31 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2017-12-28 14:15:32 [scrapy.core.engine] DEBUG: Crawled (404) <GET https://accounts.douban.com/robots.txt> (referer: None)
2017-12-28 14:15:32 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://accounts.douban.com/login> (referer: None)
登录前表单填充
登录时有验证码
根据打开的图片输入验证码:needle
登录中
2017-12-28 14:15:39 [scrapy.downloadermiddlewares.redirect] DEBUG: Redirecting (302) to <GET https://www.douban.com> from <POST https://accounts.douban.com/login>
2017-12-28 14:15:39 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.douban.com/robots.txt> (referer: None)
2017-12-28 14:15:40 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://www.douban.com> (referer: https://accounts.douban.com/login)
登录成功,当前账户为 三页的帐号

最后打印的信息为”登录成功,当前账户为 三页的帐号”,显示出我们的豆瓣账号名称,说明scrapy模拟登录豆瓣是成功的。

问题处理

在实现模拟登录过程中,碰到过几个问题在次也和大家分享下:
1.设置scrapy的user_agent
在博文scrapy爬虫之《琅琊榜2》话题title收集及词云展示我们是在settings中设置,本文是在爬虫中通过以下设置:

 headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0"}

2.scrapy 导入PIL报错如下:

>>> import PIL
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/yanggd/miniconda2/envs/scrapy/lib/python2.7/site-packages/PIL/__init__.py", line 14, in <module>
    from . import version
ImportError: cannot import name version

#解决方案:
pip install Pillow

3.scrapy提示以下错误

DEBUG:Filtered offsite request to 'accounts.douban.com': <POST https://accounts.douban.com/login>

原因:start_requests中的 url的域名不能和文件中自己配置的allowed_domains不一致,否则会被过滤掉。我之前的设置为:

allowed_domains = ['www.douban.com']

而提交表单请求的url为”https://accounts.douban.com/login“,因此出现问题。

解决办法可以通过停用过滤功能,添加”dont_filter=True”,如下所示:

return scrapy.FormRequest.from_response(response, meta={"cookiejar":response.meta["cookiejar"]}, headers=self.headers, formdata=formdata, callback=self.parse_after_login, dont_filter=True)

或者
与allowed_domains设置一致,如:

allowed_domains = ['douban.com']

猜你喜欢

转载自blog.csdn.net/yanggd1987/article/details/78920767