本帖最后由 c0ld 于 2019-7-13 20:49 编辑
这段时间在做关于爬虫的一个项目,其中遇到了一个功能需求:根据电影海报获取豆瓣影评,然后生成词云
大致的思路便是1.OCR识别从图片中获取电影名称 -> 2.爬取豆瓣影评 -> 3.提取关键词 -> 4.生成词云
在编程的过程中我遇到的问题就在于 2.爬取豆瓣影评 这一流程中,接下来列举在实现这一功能的过程中遇到的问题以及解决方案
1. 无法根据电影名称在豆瓣中找到电影详情页(豆瓣搜索结果页面使用了Ajax渲染技术)
2. 爬行速度过于缓慢(这个问题除了网络等客观原因以外,最主要的还是爬虫算法的选择上)
目前脑海中就只记得这两个问题了,如果后续想起来还有其他问题再进行补充
首先对于第一个问题出现的原因就在于 我是通过OCR文字识别从海报中提取的电影名称
意为在现阶段我们只有一个电影名称的变量,在遇到这个问题的时候我的第一反应便是看看豆瓣电影详情页的URL,是否有规律可寻
下面贴上两部电影详情页的URL:
通过以上图片我们可以观察到电影详情页的URL构成重点在于subject/后的电影编号上,但是我们发现这个编号没啥什么卵子规律,暂时放下获取电影编号的想法
于是我的方向重新放在了搜索页面,搜索页面中是存在电影详情页的URL超链接的,就像这样:
那一瞬间的我错认为问题已经被解决,当我准备分析页面结构时,我又重新回到了起点:
豆瓣在搜索页面使用了Ajax渲染技术,这种技术利用JavaScript在保证页面不被刷新,页面链接不改变的情况下与服务器交换数据并更新部分网页
意为在原页面中嵌入JavaScript脚本,通过该脚本来在原页面中拼接数据内容,像是这样:
我们爬虫此时爬行到的网页数据只是基本框架,并没有爬行到我们想要的数据,那么我们的解决方案有以下两种:
1.通过Py特定模块来实现突破Ajax页面渲染进行爬行,例如Selenium和Splash模块都是可以突破这种技术的
2.另辟蹊径
本着不作死有助于提高人生幸福感的原则,我自然是选择了第二条路-另辟蹊径,通过查询相关资料,我了解到了豆瓣提供了一个公开的API:
https://api.douban.com/v2/movie/search?q=电影名称&start=0&count=10
但是出现了一个很严肃的问题:这个API的官方接口文档丢了!
豆瓣好像忘了还有这么一个API的存在,原本应该是记录API使用说明的页面被关闭了,百度半天找到了一个私人博客里的使用总结:
https://www.cnblogs.com/oskyhg/p/9749373.html
返回数据格式如下:
可以看到这个API中返回的数据由我们想要的电影编号(就是表中的电影ID)
那么我们的问题便迎刃而解
总结一下我们最后的编程思路:
1.在API中查询该电影的ID
2.使用字符串拼接获得电影详情页URL
3.爬行电影影评
最后贴上成品代码:
[Python] 纯文本查看 复制代码
def getComment(movieName):
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
movieName = urllib.quote(movieName)
url = "https://api.douban.com/v2/movie/search?q=" + movieName + "&start=0&count=10"
movieInfoJson = requests.get(url, headers=headers).text
movieInfoJson = json.loads(movieInfoJson)
movieInfoUrl = movieInfoJson['subjects'][0]['alt']
page = 0
while page < 200:
commentList = []
commentUrl = movieInfoUrl + "/comments?start=" + str(page) + "&limit=20&sort=new_score&status=P"
html = requests.get(commentUrl, headers=headers).text
pat = '<span class="short">(.*?)</span>'
data = re.compile(pat).findall(html)
page = int(page) + 20
for i in data:
commentData = i.encode('utf-8')
commentList.append(commentData)
comment = ",".join(commentList)
commentList.append(comment)
comment = commentList[0]
return comment |