Scrapy 爬取 豆瓣电影的短评
2016-04-15 10:30
435 查看
之前爬取电影信息的时候,将电影短评的url一并存起来了。
因此爬取电影短评的时候只需将数据库中存在的url 放入start_urls中就好了。
spider.py
运行的时候出错,
显示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;
于是添加了一些代码:
这样一来,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
因此
然后发现,登陆几次后,再登陆就要输验证码。
我的解决方式是,保存验证码的url,在浏览器中打开 手动输入验证码(这样是可以) 然后和账号信息 一起提交
python PIL 可以识别验证码,用之后发现,对于豆瓣的验证码,可以说是 完全识别不出来。
这样一来 登陆之前 先看一下 有没有验证码。
如果有,就手动输入验证码,然后和账号信息一起提交
如果没有 就只发送账号信息
因此在 spider.py中添加代码:
因为我用的是 spider 不是crawlspider
因此 获取后续url的时候 用了一下代码:
这里URL 是request 中的URL
因此需要处理一下。
观察发现 豆瓣评论的url 特点
https://movie.douban.com/subject/1292052/comments?start=24&limit=20&sort=new_score
上面代码 获得的href 是 ‘?’及其后面部分。
因此URL 我们只需要’comments’及其前面的部分。
使用,python 字符串的操作。
综上:
爬短评的代码 就写好了:
如果用CrawlSpider 的话 可以省略 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 的操作。
本以为可以将一部电影的所有的短评都爬下来,
但运行之后发现一个问题,走到一定深度,会获取到一个访问会超时的页面,就继续不去了。但换一个页面,爬虫又能继续走,于是一部电影就只能获取一般甚至更少的评论数。
我也不知道是什么原因。似乎是豆瓣的原因,,,。
相关文章推荐
- Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 解决方案
- 为什么要原型设计
- php7 安装 及和php5的共存
- 加载状态栏
- 个人对webdriver的理解(一)
- SGU 125 Shtirlits(dfs)
- 六尺巷——张英
- 树莓派瞎玩~9~dns服务器
- 用栈判断表达式中的括号是否匹配
- android 屏幕适配
- 复利计算再升级
- 复利计算结对
- html 等页面防止中文出现乱码的终极解决方案
- easyui实现鼠标移到某一行,就会弹出一个提示信息效果
- Swift笔记:函数
- Java学习·String
- 浅谈Jquery中的bind(),live(),delegate(),on()绑定事件方式
- 单例模式
- Galaxy ZOO银河星空图的识别分类
- 线性表之顺序存储结构