龙空技术网

Scrapy 模拟登陆知乎——抓取热点话题

小岛动漫帝 227

前言:

现时看官们对“centos65scrapy”大致比较注意,看官们都需要知道一些“centos65scrapy”的相关知识。那么小编在网络上搜集了一些对于“centos65scrapy””的相关资讯,希望看官们能喜欢,大家快快来学习一下吧!

准备工具

在开始之前,请确保 Scrpay 正确安装,手头有一款简洁而强大的浏览器, 若是你有使用 Postman 那就更好了。

scrapy genspider zhihu

使用以上命令生成知乎爬虫,代码如下:

# -*- coding: utf-8 -*-import scrapyclass ZhihuSpider(scrapy.Spider): name = 'zhihu' allowed_domains = [''] start_urls = [''] def parse(self, response): pass

有一点切记,不要忘了启用 Cookies,切记切记 :

# Disable cookies (enabled by default)COOKIES_ENABLED = True
模拟登陆

过程如下:

进入登录页,获取 Header 和 Cookie 信息,

完善的 Header 信息能尽量伪装爬虫,有效 Cookie 信息能迷惑知乎服务端,使其认为当前登录非首次登录,若无有效 Cookie 会遭遇验证码。 在抓取数据之前,请在浏览器中登录过知乎,这样才使得 Cookie 是有效的。

Header 和 Cookie 整理如下:

headers = { 'Host': '', 'Connection': 'keep-alive', 'Origin': '', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Accept': '*/*', 'X-Requested-With': 'XMLHttpRequest', 'DNT': 1, 'Referer': '', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',}cookies = { 'd_c0': '"AHCAtu1iqAmPTped76X1ZdN0X_qAwhjdLUU=|1458699045"', '__utma': '51854390.1407411155.1458699046.1458699046.1458699046.1', '__utmv': '51854390.000--|3=entry_date=20160322=1', '_zap': '850897bb-cba4-4d0b-8653-fd65e7578ac2', 'q_c1': 'b7918ff9a5514d2981c30050c8c732e1|1502937247000|1491446589000', 'aliyungf_tc': 'AQAAAHVgviiNyQsAOhSntJ5J/coWYtad', '_xsrf': 'b12fdca8-cb35-407a-bc4c-6b05feff37cb', 'l_cap_id': '"MDk0MzRjYjM4NjAwNDU0MzhlYWNlODQ3MGQzZWM0YWU=|1503382513|9af99534aa22d5db92c7f58b45f3f3c772675fed"', 'r_cap_id': '"M2RlNDZjN2RkNTBmNGFmNDk2ZjY4NjIzY2FmNTE4NDg=|1503382513|13370a99ee367273b71d877de17f05b2986ce0ef"', 'cap_id': '"NmZjODUxZjQ0NzgxNGEzNmJiOTJhOTlkMTVjNWIxMDQ=|1503382513|dba2e9c6af7f950547474f827ef440d7a2950163"',}

在浏览器中,模拟登陆,抓取登陆请求信息。

从图中可以看到 _xsrf 参数, 这个参数与登陆验证信息无关,但很明显是由登陆页面携带的信息。 Google 查了下 xsrf 的含义:用于防范 跨站请求伪造 。

整理以上,代码如下:

loginUrl = ''siginUrl = ''def start_requests(self): return [ scrapy.http.FormRequest( self.loginUrl, headers=self.headers, cookies=self.cookies, meta={'cookiejar': 1}, callback=self.post_login) ]def post_login(self, response): xsrf = response.css( 'div.view-signin > form > input[name=_xsrf]::attr(value)' ).extract_first() self.headers['X-Xsrftoken'] = xsrf return [ scrapy.http.FormRequest( self.siginUrl, method='POST', headers=self.headers, meta={'cookiejar': response.meta['cookiejar']}, formdata={ '_xsrf': xsrf, 'captcha_type': 'cn', 'email': 'xxxxxx@163.com', 'password': 'xxxxxx', }, callback=self.after_login) ]
设置 Bearer Token

经过上述步骤登陆成功了,到此还远没有结束,这个时候尝试抓取最近热门话题,直接返回 code:401 未授权的访问。 授权信息未设置,导致了此类错误,在浏览器中追踪请求参数来侦测问题。 在浏览器的请求中,包含了 Bearer Token, 而本人在 Scrapy 中模拟的请求中未包含此信息, 所以我被服务器认定为未授权的。 通过观察发现 Bearer Token 的关键部分,就是 Cookies 中的 z_c0 包含的信息。

z_c0 包含的信息,是在登陆完成时种下的,所以从登陆完成返回的登陆信息里,获取要设置的 Cookie 信息, 然后拼接出 Bearer Token,最后设置到 Header 中。

代码整理如下:

def after_login(self, response): jdict = json.loads(response.body) print('after_login', jdict) if jdict['r'] == 0: z_c0 = response.headers.getlist('Set-Cookie')[2].split(';')[0].split( '=')[1] self.headers['authorization'] = 'Bearer ' + z_c0 return scrapy.http.FormRequest( url=self.feedUrl, method='GET', meta={'cookiejar': response.meta['cookiejar']}, headers=self.headers, formdata={ 'action_feed': 'True', 'limit': '10', 'action': 'down', 'after_id': str(self.curFeedId), 'desktop': 'true' }, callback=self.parse) else: print(jdict['error'])获取
获取数据

上述步骤后,数据获取就水到渠成了,为了检测成功与否, 把返回信息写到文件中,而且只获取前五十个,代码如下:

feedUrl = ''nextFeedUrl = ''curFeedId = 0def parse(self, response): with open('zhihu.json', 'a') as fd: fd.write(response.body) jdict = json.loads(response.body) jdatas = jdict['data'] for entry in jdatas: entry['pid'] = entry['id'] yield entry jpaging = jdict['paging'] self.curFeedId += len(jdatas) if jpaging['is_end'] == False and self.curFeedId < 50: self.nextFeedUrl = jpaging['next'] yield self.next_request(response)def next_request(self, response): return scrapy.http.FormRequest( url=self.nextFeedUrl, method='GET', meta={'cookiejar': response.meta['cookiejar']}, headers=self.headers, callback=self.parse)

最终获取的数据如下图所示:

总结

知乎的数据,只有登录完成之后,才可有效的获取,所以模拟登陆是无法忽略不管的。 所谓的模拟登陆,只是在 Scrapy 中尽量的模拟在浏览器中的交互过程,使服务端无感抓包过程。 请求中附加有效的 Cookies 和 Headers 头信息,可有效的迷惑服务端, 同时在交互的过程中,获取后续请求必要信息和认证信息,使得整个流程能不断先前。

转载 | Segmentfault

标签: #centos65scrapy