Java豆瓣电影爬虫——抓取电影详情和电影短评数据

标签: 行业资讯 爬虫 | 发表时间:2017-01-23 23:58 | 作者:liuchi1993
出处:http://www.importnew.com

动机

采集豆瓣电影数据包括电影详情页数据和电影的短评数据。

电影详情页如下图所示

需要保存这些详情字段如导演、编剧、演员等还有图中右下方的标签。

短评页面如下图所示

需要保存的字段有短评所属的电影名称,每条评论的详细信息如评论人名称、评论内容等。

数据库设计

有了如上的需求,需要设计表,其实很简单,只需要一张电影详情表movie和一张电影短评表comments,另外还需要一张存储网页提取的超链接的记录表record。

movie表

  • movieId:主键,自增长
  • Name:电影名
  • Director:导演
  • Scenarist:编剧
  • Actors:主演
  • Type:类型
  • Country:制片国家/地区
  • Language:语言
  • releaseData: 上映日期
  • Runtime: 片长
  • ratingNum:豆瓣评分
  • Tags:标签

  comments表

  • commentId:主键,自增长
  • commentInfo:评论内容
  • commentAuthor:评论者
  • commentAuthorImgUrl:评论者头像链接
  • commentVote:评论点赞数
  • commentForMovie:评论的电影名
  • recordId:链接record表,暂时未用到

  record表

  • recordId:主键,自增长
  • URL:爬取解析的超链接
  • Crawled:是否被爬过

注意:数据库设计是在不断调整的,比如之前设计了一张tags表,用于存储每部电影的标签,经过调整发现直接放到movie中作为一个字段更加方便,又比如comments表中,commentForMovie是后来加上的,方便查找当前的评论针对哪部电影。

使用的技术

语言:Java(语言是一门工具,网上用python,java,nodejs比较多)

数据库:Mysql(轻便易用)

解析页面:Jsoup(比较熟悉httpparser,虽然功能强大,但是稍显繁琐,这里用Jsoup,因为其为类javascript语法)、正则表达式(对于一些结构比较奇怪的dom结构,采用了正则表达式的方式来提取信息,其实也可以用xpath,但是xpath极易受dom结构变化而失效)

比如对于网页源码如下

<!DOCTYPE html>
<html lang="zh-cmn-Hans" class="ua-windows ua-webkit">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="renderer" content="webkit">
    <meta name="referrer" content="always">
    <title>
        肖申克的救赎 (豆瓣)
</title>

    .....

    <meta name="keywords" content="肖申克的救赎,The Shawshank Redemption,肖申克的救赎影评,剧情介绍,电影图片,预告片,影讯,在线购票,论坛,肖申克的救赎在线观看,肖申克的救赎高清,肖申克的救赎在线播放">
    <meta name="description" content="肖申克的救赎电影简介和剧情介绍,肖申克的救赎影评、图片、预告片、影讯、论坛、在线购票、肖申克的救赎在线观看、高清、在线播放">

.........                  

<div id="info">
        <span ><span class='pl'>导演</span>: <span class='attrs'><a href="/celebrity/1047973/" rel="v:directedBy">弗兰克·德拉邦特</a></span></span><br/>
        <span ><span class='pl'>编剧</span>: <span class='attrs'><a href="/celebrity/1047973/">弗兰克·德拉邦特</a> / <a href="/celebrity/1049547/">斯蒂芬·金</a></span></span><br/>
        <span class="actor"><span class='pl'>主演</span>: <span class='attrs'><a href="/celebrity/1054521/" rel="v:starring">蒂姆·罗宾斯</a> / <a href="/celebrity/1054534/" rel="v:starring">摩根·弗里曼</a> / <a href="/celebrity/1041179/" rel="v:starring">鲍勃·冈顿</a> / <a href="/celebrity/1000095/" rel="v:starring">威廉姆·赛德勒</a> / <a href="/celebrity/1013817/" rel="v:starring">克兰西·布朗</a> / <a href="/celebrity/1010612/" rel="v:starring">吉尔·贝罗斯</a> / <a href="/celebrity/1054892/" rel="v:starring">马克·罗斯顿</a> / <a href="/celebrity/1027897/" rel="v:starring">詹姆斯·惠特摩</a> / <a href="/celebrity/1087302/" rel="v:starring">杰弗里·德曼</a> / <a href="/celebrity/1074035/" rel="v:starring">拉里·布兰登伯格</a> / <a href="/celebrity/1099030/" rel="v:starring">尼尔·吉恩托利</a> / <a href="/celebrity/1343305/" rel="v:starring">布赖恩·利比</a> / <a href="/celebrity/1048222/" rel="v:starring">大卫·普罗瓦尔</a> / <a href="/celebrity/1343306/" rel="v:starring">约瑟夫·劳格诺</a> / <a href="/celebrity/1315528/" rel="v:starring">祖德·塞克利拉</a></span></span><br/>
        <span class="pl">类型:</span> <span property="v:genre">剧情</span> / <span property="v:genre">犯罪</span><br/>

        <span class="pl">制片国家/地区:</span> 美国<br/>
        <span class="pl">语言:</span> 英语<br/>
        <span class="pl">上映日期:</span> <span property="v:initialReleaseDate" content="1994-09-10(多伦多电影节)">1994-09-10(多伦多电影节)</span> / <span property="v:initialReleaseDate" content="1994-10-14(美国)">1994-10-14(美国)</span><br/>
        <span class="pl">片长:</span> <span property="v:runtime" content="142">142 分钟</span><br/>
        <span class="pl">又名:</span> 月黑高飞(港) / 刺激1995(台) / 地狱诺言 / 铁窗岁月 / 消香克的救赎<br/>
        <span class="pl">IMDb链接:</span> <a href="http://www.imdb.com/title/tt0111161" target="_blank" rel="nofollow">tt0111161</a><br>

</div>

                </div>

<div id="interest_sectl">
    <div class="rating_wrap clearbox" rel="v:rating">
        <div class="rating_logo">豆瓣评分</div>
        <div class="rating_self clearfix" typeof="v:Rating">
            <strong class="ll rating_num" property="v:average">9.6</strong>
            <span property="v:best" content="10.0"></span>
            <div class="rating_right ">
                <div class="ll bigstar50"></div>
                <div class="rating_sum">
                    <a href="collections" class="rating_people"><span property="v:votes">740373</span>人评价</a>
                </div>
            </div>
        </div>

                <span class="stars5 starstop" title="力荐">
                    5星
                </span>
                <div class="power" style="width:64px"></div>
                <span class="rating_per">81.5%</span>
                <br />

                <span class="stars4 starstop" title="推荐">
                    4星
                </span>
                <div class="power" style="width:12px"></div>
                <span class="rating_per">16.2%</span>
                <br />

                <span class="stars3 starstop" title="还行">
                    3星
                </span>
                <div class="power" style="width:1px"></div>
                <span class="rating_per">2.1%</span>
                <br />

                <span class="stars2 starstop" title="较差">
                    2星
                </span>
                <div class="power" style="width:0px"></div>
                <span class="rating_per">0.1%</span>
                <br />

                <span class="stars1 starstop" title="很差">
                    1星
                </span>
                <div class="power" style="width:0px"></div>
                <span class="rating_per">0.1%</span>
                <br />

    </div>
        <div class="rating_betterthan">
            好于 <a href="/typerank?type_name=剧情&type=11&interval_id=100:90&action=">99% 剧情片</a><br/>
            好于 <a href="/typerank?type_name=犯罪&type=3&interval_id=100:90&action=">99% 犯罪片</a><br/>
        </div>
</div>

            </div>

.........

    <!-- sindar19a-docker-->

  <script>_SPLITTEST=''</script>
</body>

</html>

可以通过如下代码来解析相应字段(其中有用Jsoup和正则表达式的)

for (Element info : infos) {
    if (info.childNodeSize() > 0) {
        String key = info.getElementsByAttributeValue("class", "pl").text();
        if ("导演".equals(key)) {
            movie.setDirector(info.getElementsByAttributeValue("class", "attrs").text());
        } else if ("编剧".equals(key)) {
            movie.setScenarist(info.getElementsByAttributeValue("class", "attrs").text());
        } else if ("主演".equals(key)) {
            movie.setActors(info.getElementsByAttributeValue("class", "attrs").text());
        } else if ("类型:".equals(key)) {
            movie.setType(doc.getElementsByAttributeValue("property", "v:genre").text());
        } else if ("制片国家/地区:".equals(key)) {
            Pattern patternCountry = Pattern.compile(".制片国家/地区:</span>.+[\\u4e00-\\u9fa5]+.+[\\u4e00-\\u9fa5]+\\s+<br>");
            Matcher matcherCountry = patternCountry.matcher(doc.html());
            if (matcherCountry.find()) {
                movie.setCountry(matcherCountry.group().split("</span>")[1].split("<br>")[0].trim());// for example: >制片国家/地区:</span> 中国大陆 / 香港     <br>
            }
        } else if ("语言:".equals(key)) {
            Pattern patternLanguage = Pattern.compile(".语言:</span>.+[\\u4e00-\\u9fa5]+.+[\\u4e00-\\u9fa5]+\\s+<br>");
            Matcher matcherLanguage = patternLanguage.matcher(doc.html());
            if (matcherLanguage.find()) {
                movie.setLanguage(matcherLanguage.group().split("</span>")[1].split("<br>")[0].trim());
            }
        } else if ("上映日期:".equals(key)) {
            movie.setReleaseDate(doc.getElementsByAttributeValue("property", "v:initialReleaseDate").text());
        } else if ("片长:".equals(key)) {
            movie.setRuntime(doc.getElementsByAttributeValue("property", "v:runtime").text());
        }
    }
}
movie.setTags(doc.getElementsByClass("tags-body").text());
movie.setName(doc.getElementsByAttributeValue("property", "v:itemreviewed").text());
movie.setRatingNum(doc.getElementsByAttributeValue("property", "v:average").text());

对于服务端返回不同状态的http status,本程序对于如304,401,403,404等都采取了丢弃处理,不作解析。

效果展示

  record表记录

  movie表记录

  comments表记录

以上只是一个爬取数据的后台实现雏形,还有很多细节的问题需要解决。后期可能会补上环境搭建以及遇到的问题和解决方法相关的文章。

Java豆瓣电影爬虫——使用Word2Vec分析电影短评数据

Java豆瓣电影爬虫——小爬虫成长记(附源码)

程序爬取控制在豆瓣可接受范围内,不会给豆瓣服务器带来很大的压力,写此程序也是个人把玩,绝无恶意,万望豆瓣君谅解^_^

可能感兴趣的文章

相关 [java 豆瓣 电影] 推荐:

Java豆瓣电影爬虫——抓取电影详情和电影短评数据

- - ImportNew
采集豆瓣电影数据包括电影详情页数据和电影的短评数据. 需要保存这些详情字段如导演、编剧、演员等还有图中右下方的标签. 需要保存的字段有短评所属的电影名称,每条评论的详细信息如评论人名称、评论内容等. 有了如上的需求,需要设计表,其实很简单,只需要一张电影详情表movie和一张电影短评表comments,另外还需要一张存储网页提取的超链接的记录表record.

阿北:豆瓣电影评分八问

- - 博客园_新闻
这是一篇豆瓣创始人&CEO 阿北(杨勃)刚刚发表的 长文,始终被认为理想主义的阿北,在文中阐明了豆瓣电影评分的原则和做法,用以保护公众对豆瓣评分的信任. 随着“豆瓣的电影评分在影视行业的影响越来越大”,阿北说豆瓣收到的威逼利诱也多起来……以下为全文. (豆瓣 CEO 阿北,图片来自 Qdaily).

豆瓣9.0分以上的好电影,值得收藏

- sky - 情迷好莱坞 – Mtime时光网
地球脉动 Planet Earth. 导演 : Alastair Fothergill. 主演 : David Attenborough/Sigourney Weaver. 评分:9.7  ★★★★★. 肖申克的救赎 The Shawshank Redemption. 导演 : Frank Darabont.

豆瓣电影2011年度清单总汇

- - 人在旅“图”
2011豆瓣电影年度总榜单,豆瓣红人影志整理,很全很强大. 2011是否遗漏了哪些好电影,参考比对一下吧. 所选范畴为2011年上映或发行的国内外所有影片,根据豆瓣用户评分+看过(在看)人数排序. ★  2011豆瓣电影【欧美20佳】. 勇士 Warrior 8.8 17872. 浮生一日 Life in a Day 8.8 11879.

算法工程师如何改进豆瓣电影 TOP250

- - 豆瓣blog
影迷们经常关注的电影排行榜里,一部由100人评出9.0分的电影,和一部由10000人评出8.0分的电影,谁应该排在前面呢. 这是我们算法工程师时常会面对的问题. 一些深度影迷可能会想到 imdb.com (互联网电影数据库) 所采用的贝叶斯公式[见附注],这个公式的思路就是通过每部影片的[评分人数]作为调节排序的杠杆:如果这部影片的评分人数低于一个预设值,则影片的最终得分会向全部影片的平均分拉低.

使用Spark MLlib给豆瓣用户推荐电影

- - 鸟窝
推荐算法就是利用用户的一些行为,通过一些数学算法,推测出用户可能喜欢的东西. 随着电子商务规模的不断扩大,商品数量和种类不断增长,用户对于检索和推荐提出了更高的要求. 由于不同用户在兴趣爱好、关注领域、个人经历等方面的不同,以满足不同用户的不同推荐需求为目的、不同人可以获得不同推荐为重要特征的个性化推荐系统应运而生.

为豆瓣电影实现User-based协同过滤的推荐系统

- - 鸟窝
协同过滤(Collaborative Filtering),简单来说是利用某兴趣相投、拥有共同经验之群体的喜好来推荐使用者感兴趣的信息,个人透过合作的机制给予信息相当程度的反馈(如评分)并记录下来以达到过滤的目的进而帮助别人筛选信息,反馈不一定局限于特别感兴趣的,特别不感兴趣信息的纪录也相当重要,比如浏览信息,收藏,分享,点击等.

为豆瓣电影实现Item-based协同过滤的推荐系统

- - 鸟窝
前面的两篇文章分别使用Spark mllib ALS实现了Model-based协同过滤推荐系统和使用Mahout实现了User-based的协同过滤推荐系统. 我们再来回顾一下item-base CF算法的特点:. 物品数明显小于用户数的场合,否则物品相似度矩阵计算代价很大. 适合长尾物品丰富,用户个性化需求强的领域.

【外刊IT评论网】电影《Java风云》预告片

- 老五 - 外刊IT评论
我在youtube上发现这个视频,youbube竟然把这个视频列为少儿不宜. 所以,提醒各位观众,观看前请三思. 里面确实有一个镜头涉及少儿不宜,奇怪为什么美国的审查制度这么严. 至于视频的内容,纯搞笑的,关于Java和.Net之争,大家就当一个笑话看看吧. 本文来自外刊IT评论网(www.aqee.net),原始地址:电影《Java风云》预告片.

豆瓣电影2016榜单:有人选择看到这世间的丑恶,有人选择看到美好

- - PingWest品玩
面对近日的“恶评”风波,豆瓣的回应是一份榜单,一份满载好电影的榜单. 28 日晚上,豆瓣电影发布一年一度的榜单. 这份榜单是基于 2016 年豆瓣用户在豆瓣平台对影视作品的评分、标记和访问数据,再结合评价人数和上映时间,综合考虑而成. 今年豆瓣有哪些喜闻乐见的好电影. 2016 评分最高的华语电影:《 驴得水》 8.3.