这个网上有个通用的教程,然而为这个教程已经花费了太多时间进行调试,和知乎上的朋友交流,很多人也是这个地方遇到了问题,最后的结果。。是放弃了crawlspider。。
先贴下 这个链接。。。http://ju.outofmemory.cn/entry/105646 谨慎。。
针对上面这个教程,遇到的几点问题:
问题1:知乎的登陆url不再是/login了,根据email和phonenum分为/login/phone_num和login/email。因此start_requests的里的url需要更改
问题2:根据文档中,模拟登陆的FormRequest.from_response,在after_login中print response.body发现还是登陆页,这个也有人遇到,但是根据他的解释应该是登陆成功,但是获取url的方法没有调用到。。这个我没做,不过我自己放弃了,直接使用formRequest提交数据,并且FormRequest.from_response貌似是get方法,改成“method=post”,返回403。不知道是不是method不能改还是其他原因。
formRequest可以设置method为post。但是在after_login中发现after_login中 打印response.body,还是登陆页
问题3:最初针对问题2,我的解决思路是,在after_login里,重新使用登陆后的cookie重新访问zhihu.com,在make_request_from_url里,结果返回了
no more duplicates will be shown(see dupefilter_debug to show all duplicates)
问题4:在post_login里使用formRequest后,在after_login中 打印response.body,返回{r'0',msg:''}调用构建个人主页的request的话,是可以获取到的,response但是设置start_urls为people/****后,yield make_request_from_url(start_urls)会出现302重定向问题,同时parse_page里解析依旧是首页
问题5:拿一个不用登陆的url测试“https://www.zhihu.com/question/21872451“ :
在after_login里:
return [Request("https://www.zhihu.com/question/21872451",meta={'cookiejar':response.meta['cookiejar']},headers = self.headers_zhihu,callback=self.parse_page)]
发现可以解析当前页,并且但是rule规则不生效,并且”https://www.zhihu.com/question/21872451“后台parse_page调用了两次,但是当前页面的登陆状态时可以获取到的
”
问题6:针对5,反过来测试下,修改start_url=”https://www.zhihu.com/question/21872451“,依然调用yield make_request_from_url(start_urls),发现登陆状态又获取不到了;继续改回
return [Request("https://www.zhihu.com/question/21872451",meta={'cookiejar':response.meta['cookiejar']},headers = self.headers_zhihu,
#callback=self.parse_page
)]
但是把callback注释掉,发现/question/21872451 解析不到,同时,rule生效,调用parse_page,登陆状态没有。
总结:
1 make_requests_from_urls:如果不设置回调函数,会调用默认的parse,同时调用原生态的make_request_from_urls不会携带哦cookie,所以要复写,同时,如果callback也设置和rule一致的话,会出现首页解析正确,rule不生效(有人说是因为冲突,因此我试了下更改make_requests_from_urls,callback=‘parse_item’,发现rule还是不生效,parse_page没有执行,所以问题应该不在那里),反过来,如果callback不设置的话,rule生效,但是首页解析不到,且无登陆状态。
2 crawlspider的rule是不能自动携带cookie构建request,同时不能复写parse(),这个是官方文档的说明,如果重写parse会运行失败。
结论:放弃了crawlspider,选择复写parse(),在parse中构建自己的request
最终形成的登陆
zhihu.py
# -*- coding: utf-8 -*-
import scrapy
from bs4 import BeautifulSoup
from MyTest.items import *
from scrapy.http import Request, FormRequest
from scrapy.selector import Selector
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.spider import BaseSpider
import urlparse
from scrapy import log
class ZhihuSpider(BaseSpider):
name = "zhihu"
#allowed_domains = ["zhihu.com"]
start_urls = (
'https://www.zhihu.com/',
)
headers_zhihu = {
'Host':'www.zhihu.com ',
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding':'gzip,deflate,sdch',
'Referer':'https://www.zhihu.com ',
'If-None-Match':"FpeHbcRb4rpt_GuDL6-34nrLgGKd.gz",
'Cache-Control':'max-age=0',
'Connection':'keep-alive'
# 'cookie':cookie
}
def start_requests(self):
return [Request("https://www.zhihu.com/login/phone_num",meta={'cookiejar':1},headers = self.headers_zhihu,callback=self.post_login)]
def post_login(self,response):
print 'post_login'
xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0] #不见【0】输出错误
print 'xsrf'+xsrf
return [FormRequest('https://www.zhihu.com/login/phone_num',
method='POST',
meta = {
'cookiejar': response.meta['cookiejar'],
'_xsrf':xsrf
},
headers = self.headers_zhihu,
formdata = {
'phone_num':'******', #这里的参数值不能去掉''
'password':'*****',
'_xsrf':xsrf
},
callback = self.after_login,
#dont_filter = True
)]
def after_login(self,response):
print 'after_login'
print response.body # 返回msg
for url in self.start_urls:
print 'url...................'+url
yield self.make_requests_from_url(url,response)
def make_requests_from_url(self, url,response):
return Request(url,dont_filter=True, meta = {
'cookiejar':response.meta['cookiejar'],
'dont_redirect': True,
'handle_httpstatus_list': [301,302]
},
# callback=self.parse
)
def parse(self, response):
items = []
problem = Selector(response)
item = ZhihuItem()
name = problem.xpath('//span[@class="name"]/text()').extract()
print name
item['name'] = name
urls = problem.xpath('//a[@class="question_link"]/@href').extract()
print urls
item['urls'] = urls
print 'response ............url'+response.url
item['url'] = response.url
print item['url']
items.append(item)
yield item #返回item
for url in urls:
print url
yield scrapy.Request(urlparse.urljoin('https://www.zhihu.com', url),dont_filter=True, #直接使用url会报错
meta = {
'cookiejar':response.meta['cookiejar'], #设置cookiejar
'dont_redirect': True, #防止重定向
'handle_httpstatus_list': [301,302]
},
callback=self.parse
)
#return item
COOKIES_ENABLED = True
COOKIES_DEBUG = True
其他的处理和之前爬取qiubai差不多,就不多解释了
遗留问题:为什么make_request_from_url设置回调后,rule不生效
start_urls如果设置符合rule规则,为什么也没做解析