您的位置:首页 > 其它

Scrapy 爬取 豆瓣电影的短评

2016-04-15 10:30 435 查看
之前爬取电影信息的时候,将电影短评的url一并存起来了。

因此爬取电影短评的时候只需将数据库中存在的url 放入start_urls中就好了。

spider.py

# -*- coding: utf-8 -*-
from scrapy.selector import Selector
from scrapy.spiders import Spider
from scrapy.http import Request ,FormRequest
from comments.items import CommentsItem
import scrapy
from scrapy import log
import MySQLdb

class CommentSpider(Spider):
name = "comments"
#allowed_domains=["movie.douban.com"]
db = MySQLdb.connect("localhost","root","123456","python" )
cursor = db.cursor()
#在爬取电影信息时已经将评论的链接也抓到数据库中(comment_url),  从数据中找到地址  作为 start_urls
cursor.execute("select comment_url from doubanmovie")
#data = cursor.fetchone() # 取一条
data = cursor.fetchall() #取所有
start_urls = data
def parse(self,response):
sel = Selector(text=response.body)
Url = response.url
start_index = Url.find('comments')
URL = Url[0:start_index+8]
ID = filter(str.isdigit,URL)
comments = sel.xpath('//*[@class="comment-info"]')
for comment in comments:
item = CommentsItem()
item['ID'] = ID
item['user_name'] = comment.xpath('a/text()').extract()
item['user_score'] = comment.xpath('span[1]/@title').extract()
yield item
for url in sel.xpath("//*[@class='next']/@href").extract():
yield Request(URL+url,callback=self.parse)


运行的时候出错,

显示TypeError(‘Request url must be str or unicode, got %s:’ % type(url).name).

后来发现 是因为 从数据库中取数据,data是 tuple 格式。

直接 start_urls = data; 不合适。因为 在scrapy中 start_urls是List,而且 start_urls中的元素应该是string;

于是添加了一些代码:

temp = list(data)
start_urls = []
for i in range(len(temp)):
tem = str(temp[i])
tem2 = tem[2:len(tem)-3]
start_urls.append(tem2)


这样一来,start_urls 就符合格式了。

然后就是模拟登陆了。

豆瓣爬取短评的时候,不登录只能爬取前几页。这显然是不够的。

scrapy模拟登陆可以使用

from scrapy.http import Request ,FormRequest

而且,scrapy自动处理cookie.

关于模拟登陆,文档上更详细,也有例子:

https://scrapy-chs.readthedocs.org/zh_CN/0.24/topics/request-response.html#scrapy.http.FormRequest.from_response

看 douban 登陆界面的html

<div class="item">
<label>帐号</label>
<input id="email" name="form_email" type="text" class="basic-input"
maxlength="60" value="邮箱/手机号" tabindex="1"/>
</div>
<div class="item">
<label>密码</label>
<input id="password" name="form_password" type="password" class="basic-input" maxlength="20" tabindex="2"/>
</div>


因此

formdata={
'form_email': '账号',
'form_password': 'passward'
},


然后发现,登陆几次后,再登陆就要输验证码。

我的解决方式是,保存验证码的url,在浏览器中打开 手动输入验证码(这样是可以) 然后和账号信息 一起提交

python PIL 可以识别验证码,用之后发现,对于豆瓣的验证码,可以说是 完全识别不出来。

这样一来 登陆之前 先看一下 有没有验证码。

如果有,就手动输入验证码,然后和账号信息一起提交

如果没有 就只发送账号信息

因此在 spider.py中添加代码:

def start_requests(self):
yield Request("https://accounts.douban.com/login?source=movie", meta={'cookiejar':1},callback=self.post_login)

def post_login(self,response):
print 'Preparing login'
sel = Selector(response)
nodes = sel.xpath("//*[@class='captcha_image']/@src").extract()
if nodes :
print nodes
xerf = raw_input()
return scrapy.FormRequest.from_response(
response,
formdata={
'captcha-solution': xerf,
'form_email': '账号',
'form_password': 'password'
},
callback=self.after_login
)

return scrapy.FormRequest.from_response(
response,
formdata={'form_email': '账号',
'form_password': 'password'
},
callback=self.after_login
)
def after_login(self,response):
#check login succeed before going on
if "authentication failed" in response.body:
self.log("login failed", level = log.ERROR)
for url in self.start_urls :
print url
yield self.make_requests_from_url(url)

#-----------


因为我用的是 spider 不是crawlspider

因此 获取后续url的时候 用了一下代码:

for url in sel.xpath("//[@class='next']/@href").extract():
yield Request(URL+url,callback=self.parse)


这里URL 是request 中的URL

因此需要处理一下。

观察发现 豆瓣评论的url 特点

https://movie.douban.com/subject/1292052/comments?start=24&limit=20&sort=new_score

上面代码 获得的href 是 ‘?’及其后面部分。

因此URL 我们只需要’comments’及其前面的部分。

使用,python 字符串的操作。

Url = response.url
start_index = Url.find('comments')
#start_index 保存的是 comments 前一个字符的位置
URL = Url[0:start_index+8]
#将 comments 加上


综上:

爬短评的代码 就写好了:

# -*- coding: utf-8 -*-
from scrapy.selector import Selector
from scrapy.spiders import Spider
from scrapy.http import Request ,FormRequest
from comments.items import CommentsItem
import scrapy
from scrapy import log
import MySQLdb

class CommentSpider(Spider):
name = "comments"
#allowed_domains=["movie.douban.com"]
db = MySQLdb.connect("localhost","root","123456","python" )
cursor = db.cursor()
#在爬取电影信息时已经将评论的链接也抓到数据库中(comment_url),  从数据中找到地址  作为 start_urls
cursor.execute("select comment_url from doubanmovie")
#data = cursor.fetchone()
data = cursor.fetchall()

temp = list(data)
start_urls = []
for i in range(len(temp)):
tem = str(temp[i])
tem2 = tem[2:len(tem)-3]
start_urls.append(tem2)
print start_urls
def start_requests(self):
yield Request("https://accounts.douban.com/login?source=movie", meta={'cookiejar':1},callback=self.post_login)

def post_login(self,response):
print 'Preparing login'
sel = Selector(response)
nodes = sel.xpath("//*[@class='captcha_image']/@src").extract()
if nodes :
print nodes
xerf = raw_input()
return scrapy.FormRequest.from_response(
response,
formdata={
'captcha-solution': xerf,
'form_email': '1491651205@qq.com',
'form_password': 'wx950417'
},
callback=self.after_login
)

return scrapy.FormRequest.from_response(
response,
formdata={'form_email': '1491651205@qq.com',
'form_password': 'wx950417'
},
callback=self.after_login
)
def after_login(self,response):
#check login succeed before going on
if "authentication failed" in response.body:
self.log("login failed", level = log.ERROR)
for url in self.start_urls :
print url
yield self.make_requests_from_url(url)

#-----------

def parse(self,response):
sel = Selector(text=response.body)
Url = response.url
start_index = Url.find('comments')
URL = Url[0:start_index+8]
ID = filter(str.isdigit,URL)
comments = sel.xpath('//*[@class="comment-info"]')
for comment in comments:
item = CommentsItem()
item['ID'] = ID
item['user_name'] = comment.xpath('a/text()').extract()
item['user_score'] = comment.xpath('span[1]/@title').extract()
yield item
for url in sel.xpath("//*[@class='next']/@href").extract():
yield Request(URL+url,callback=self.parse)


如果用CrawlSpider 的话 可以省略 URL 的操作。

本以为可以将一部电影的所有的短评都爬下来,

但运行之后发现一个问题,走到一定深度,会获取到一个访问会超时的页面,就继续不去了。但换一个页面,爬虫又能继续走,于是一部电影就只能获取一般甚至更少的评论数。

我也不知道是什么原因。似乎是豆瓣的原因,,,。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: