模仿网上的Scrapy程序,自己写了个爬虫。虽然是模仿,但是呢,好多都是自己去实践错了对了,整天都在苦闷之中度过,没办法,我的IQ较低,总是要学很久才能懂。。。。。。。
ps:运行这个程序你要安装scrapy、Selector等等(好多好烦,若是出错了,找找版本原因,因为我上次在ubuntu上就是scrapy0.14的,运行错误。。)
首先爬知乎首页,你第一得做好登录(这个woc郁闷死了,官方文档看了很久没看到,后来看了某些博客,尼玛就在官方文档里啊 ,怪没用心去理解:))
直接上代码把,因为解释好多都在代码中。。。
zhihu/zhihu/spiders/zhihu_spider.py :
<pre name="code" class="python">#!/usr/bin/env python
# -*- coding:utf-8 -*-
import bs4
from scrapy.selector import Selector
from scrapy.spider import Spider
from scrapy.item import Item,Field
from scrapy.http import Request,FormRequest
from zhihu.items import ZhihuItem
import urllib
import urllib2
import cookielib
import re
#from zhihu.items import ZhihuItem
class ZhihuSpider(Spider):
"""通过知乎首页先获取一个用户的信息"""
name="zhihuspider"
#allowed_domains=["zhihu.com"]
#先前没加#时,用户的知乎网址被过滤掉了,后来查了下官方文档,Filtered offsite request to 'www.othersite.com':但是,http://www.zhihu.com/people/nihisic 是属于zhihu.com的啊 为什么还会被过滤掉?
start_urls=["http://www.zhihu.com/",]
"""~~~~~~~~~~~~~~~~~~~~~~~"""
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip,deflate",
"Accept-Language": "en-US,en;q=0.8,zh-TW;q=0.6,zh;q=0.4",
"Connection": "keep-alive",
"Content-Type":" application/x-www-form-urlencoded; charset=UTF-8",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36",
"Referer": "http://www.zhihu.com/"
}
def start_requests(self):
return [Request("https://www.zhihu.com/login", meta = {'cookiejar' : 1}, callback = self.post_login)]
#当我们单个spider中每次只有一个request时候,因为默认是使用一个cookiejar来处理,
# 所以我们在发出request的时候,不需要手动使用meta来给它布置cookiejar,
# 但是当单个spider多个request的时候,因为返回的每个response要求下一个request带的cookie都不同,
# 所以每一次都要手动给每个request添加cookiejar来记录
def post_login(self, response):
print 'Preparing login'
#下面这句话用于抓取请求网页后返回网页中的_xsrf字段的文字, 用于成功提交表单
xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]
print xsrf#这个是看了某个博客写的登录知乎的,我不知道提交的还有这个xsrf
#FormRequeset.from_response是Scrapy提供的一个函数, 用于post表单
#登陆成功后, 会调用after_login回调函数
return [FormRequest.from_response(response,#模拟头部信息
meta = {'cookiejar' : response.meta['cookiejar']},
headers = self.headers, #注意此处的headers
formdata = {
'_xsrf': xsrf,
'email': 'xxxxxxxxxxxx',
'password': 'xxxxxxx'
},
callback = self.parse_page,
dont_filter = True
)]#这个官方文档都有。。。。我只是没有好好的理解。。。。
def after_login(self, response) :
for url in self.start_urls :
yield self.make_requests_from_url(url)
"""~~~~~~~~~~~~~~~~~~~~~~~"""
def parse_page(self,response):
title=[]
link=[]
sel=Selector(response)
sites=sel.xpath('//div[@class="feed-main"]/div[@class="source"]')
for site in sites:
title=site.xpath('a/@title').extract()#因为知乎话题的话是没有title这个标签的,所以抓出来是空白,若是知乎用户的话就不是空白。
link=site.xpath('a/@href').extract()
#出现了Request url must be str or unicode这个错,后解决了
if title:#判定是否是用户,若不是用户,title为空
yield Request(url=link[0],callback=self.parse2)#url变成了这样url=[u'http://...']
if not title:
yield Request(url='http://www.zhihu.com'+link[0],callback=self.parse2)
def parse2(self,response):
"""
解析用户的详细信息页面,使用bs4
"""
soup = bs4.BeautifulSoup(response.body,from_encoding="utf8")
userInfo1 = soup.findAll('div', attrs={'class':'title-section ellipsis'})
#这是个人知乎用户,因为class不同,所以与知乎话题userinfo2分开,下面筛的是知乎话题。
userInfo2 = soup.findAll('div', attrs={'class':'zu-main-content'})
if userInfo2:
# userInfo2 = userInfo2[0]
# item = ZhihuItem()
# item['signature'] = "".join(userInfo2.findAll('div', attrs={'class':'zm-editable-content'})[0].strings)
# item['yonghu'] = "".join(userInfo2.findAll('h1', attrs={'class':'zm-editable-content'})[0].strings)
pass#啊西吧 若是取消#,则会出现list out of range,又是这种错误,好烦。。。。直接pass
# print item['signature']
# print item['yonghu']
# return item
if userInfo1:
userInfo1 = userInfo1[0]
item = ZhihuItem()
item['signature'] = "".join(userInfo1.findAll('span', attrs={'class':'bio'})[0].strings)
item['yonghu'] = "".join(userInfo1.findAll('span', attrs={'class':'name'})[0].strings)
##这个我抓取的是他的用户名与签名。。。。虽说爬虫很小,但是思路最重要。
print item['signature']
print item['yonghu']
return item
zhihu/zhihu/items.py:
from scrapy.item import Item, Field
class ZhihuItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
yonghu=scrapy.Field()
signature=scrapy.Field()
pass
然后scrapy crawl zhihuspider~~~~~~~~
ps:如果在item['signature']... list index out of range报错,说明
那个人的签名太长了..... :)..哈哈
昨天考完46级。qusiba。