0 前言
先说说看这篇博客你能知道什么:1 腾讯、网易、新浪不同新闻的地址格式以及评论内容的地址格式(返回数据为json的异步接口);2 一些比较通用的设计方法,对软件设计的菜鸟可能有帮助;
之前也说了要写这篇博客,现在终于写出来了。我的毕业设计的指导老师说毕设论文的字数不够……所以我决定把这些本不应该出现在论文中的实现细节凑到论文中。至于下面说到的东西要解决什么问题,各位可以先看看这个网站(我毕设的初步结果,目前还在优化中,包括代码结构还有UI设计):http://news.reetsee.com/
凡是这篇博文中出现超链接的地方,可以放心点击,新的页面会在新标签中打开而不会直接在当前的标签打开。
这个网站要实现以下功能:从腾讯新闻、网易新闻、新浪新闻中(当然以后可能会更多其它新闻网站)通过代码自动分析出哪些新闻内容是相似的,然后把相似的内容组织到一起,例如三个网站都有“北京成功申奥”这样的新闻,这个网站会自动把三条新闻归到一起,然后把三个新闻网站的热门评论都下载下来,按照时间排序,最后通过代码计算出一段“评论概括”,因为有的人很懒,看新闻基本就是看了标题然后看评论,看评论可能只看热门评论,看热门评论可能还看那种被顶得最多的,所以我就这么帮下这些懒人了……哈哈哈。
网站打开得有点慢,这个是因为我的代码写得不够好,在百度也看到很多牛逼的技术内容,回头看看这个毕设的各种设计,觉得有点丢脸,迟点重构····目前先凑合着用。咳咳,跑题了,这个网站的所有内容可以说都是通过爬虫抓取下来了,我的工作只不过是将爬虫获取的内容进行了组织然后重新展现。
这篇博客的内容仅仅是说一下爬虫是怎么写的,完全不会涉及分析新闻相似的算法是怎么样的以及对热门评论进行概括的算法是怎么样的。
那么下面开始。
1 新闻格式规范化
我在同学介绍下选择了Python的Scrapy爬虫框架进行爬虫编写(最近我自己用PHP写了个爬虫框架Phpfetcher,可以参见这里:http://blog.reetsee.com/archives/366)。要在自己的网站上展示新闻内容,就应该将下载好的新闻按照统一的格式处理好,这样前端(网页端)才能够方便地处理、展示。一篇新闻有以下几个需要关注的地方:
- 新闻标题
- 新闻正文
- 新闻时间
由于要知道新闻的来源以及对应的评论,所以加上这两项:4. 新闻来源,5. 新闻评论地址。
那么最终在我这里,一篇处理后的新闻格式应该是这样的(这里使用类似json的格式表示,“[]”表示一个数组,“{}”表示一个字典):
03 | 'date' : '时间(长度8位,如20140501)' , |
05 | 'link' : '新闻详细内容页面的地址' , |
10 | 'link' : '新闻对应的评论页面地址' , |
如果有人问既然已经有了新闻的地址页面,为什么还要将新闻标题、新闻正文这些内容保存到本地呢?因为要在本地对新闻进行分类,就必须将这些内容下载下来。
上面的格式只是一个初步的统一格式,最终的格式相比这个可能会有小变化,这个后面再说。
2 评论格式规范化
要在我的网站对评论进行展示,就要有统一的格式,通常评论的要素包括三个:
- 用户名
- 评论时间
- 评论内容
由于我要标注评论的来源,所以再加一个:4. 评论来源,那么最终被我处理过的评论格式如下:
那么最终重新按照时间排序后的评论列表格式应该是像下面这样的:
这里先规范好最终的评论格式,下面针对评论部分的讲解设计就有头有据了。
另外就是评论并不需要爬虫下载!因为评论是实时更新的,不像新闻,基本上发布了就不怎么变化了。因为评论的内容是在用户点击某条新闻后才通过HTTP请求获取的。
3 URL规则分析
3.1 腾讯新闻
这个是其中一个功能,还有很多非常赞的功能。
回到正文。
要注意的是,评论页ID是大于10^9的;新闻ID不是一个数字,
注意真的不是一个数字!而是一个只包含数字的字符串,例如它可能是“000123”。
现在开始分析一下腾讯新闻评论中的字段,比起网易新闻的简直是太臃肿了,那么就直接说关心的内容了(请直接点击上面热门评论的那条URL、或者复制到你的地址栏,回车后查看结果,与下面的内容比对):
- targetid就是新闻的id;
- time就是时间戳,有了这个可以转换成公元时间;
- content就是回复的内容(这位网友真是热心回复这么多);
- up就是人家给的赞的数量;
- userinfo中的nick就是用户名了,后面竟然还有对应的腾讯微博的用户信息。
02 | id: "5828439023791190273" , |
07 | timeDifference: "01月13日 18:15:50" , |
09 | content: "很高兴看到中央军委日前印发《关于军队贯彻落实〈党政机关厉行节约反对浪费条例〉的措施》,规定今后所有公务用车采购国产自主品牌,其实不光是汽车,像电脑、打印机、扫描仪、复印机、服务器、网络设备、软件等产品更要带头采购国产自主品牌,防止军队内部机密资料遭受国外网络黑客攻击!希望中央军委、中国海陆空军队能够切实担负起捍卫国土、捍卫钓鱼岛的职责!其实中国的部队,大部分军官素质是好的,但也有相当一部分军官也十分腐败,作风腐化堕落,为人霸道欺负新兵,道德品质极差;艰苦奋斗、勤俭建军的思想有所淡化;革命意志、进取精神有所退化;铺张浪费、大手大脚现象有所抬头。加强军队的反腐倡廉建设对于巩固党的执政地位、树立中国军队的新形象、提升国防战斗力十分重要。要保卫好祖国国土完整,加强军队作风建设和反腐倡廉建设责任重大。“物必自腐,而后虫之”,如果任由各种腐败作风在军队系统漫延,将使中国军队的整体战斗力、中国军官的整体政治素质大大下降,后果不堪设想!希望中央军委一定要在全军大力开展创先争优活动,加强中国军人综合素质建设与作风建设,全面推广党风廉政建设巡视检查制度,大力清除军队内部的腐败分子,大力整顿军队内部的“吃喝玩乐嫖赌、卖官鬻爵收受贿赂违规提拔干部”等各类不正之风,营造“勤于学习、善于学习、钻研技术、廉洁从业”的良好氛围,铸造一支英勇善战、战斗力凝聚力号召力超强的中国军队!同时中国军队应该坚持人性化细节化管理,对于长期夫妻两地分居的军官、军人要免费发放性慰器,防止他们流入社会进入嫖娼卖淫场所影响中国军队形象!希望中国能够集国家和中华民族的坚强意志,大力加强自主创新型国家建设,努力攻克在大型民用飞机、军用飞机、导弹系统、航空母舰等制约国家核心技术的关键高端产业领域,早日使我国的民用与军用飞机、导弹、航空母舰早日上市,彻底摆脱对欧洲、美国、日本在先进技术上的制约,成为一个装备制造强国!中国不能搞、不会搞军事扩张但也绝不能太懦弱,一定要夯实军事装备,提升军队战斗力,保护好国土、海域的安全,捍卫民族尊严!" , |
22 | uidex: "ec52a391823814524e8446efa3bd6a48d9" , |
还记得在“评论规范化”中定的格式吗?现在我们就从上面的json格式找到一个将其规范化的方法,假设热门评论连接中返回的json格式的变量名为js,i为遍历时的下标,那么用下面这个方法进行评论格式的规范化:
3 | 'user' : js[ 'data' ][ 'commentid' ][i][ 'userinfo' ][ 'nick' ], |
4 | 'time' : js[ 'data' ][ 'commentid' ][i][ 'time' ], |
5 | 'content' : js[ 'data' ][ 'commentid' ][i][ 'content' ] |
腾讯新闻的算是搞掂了。
3.2 网易新闻
新闻页面获取评论数量的方法:查找”
totalCount“就是评论数目,新闻ID就是”
threadId“,
讨论版面就是”
boardId“,这个js是inline的,直接就放到网页中了:
01 | <script type= "text/javascript" > |
02 | if ( typeof isForceShowComment != "undefined" ) { |
03 | isShowComments = isForceShowComment; |
11 | var replyCount = 10068, |
13 | threadId = "9IISVTCG0001124J" , |
14 | boardId = "news_guonei8_bbs" , |
17 | NTES( ".js-tielink" ).attr( "href" , "http://comment." + host + ".163.com/" + boardId + "/" + threadId + ".html" ) |
18 | NTES( ".js-tiecount" ).attr( "innerHTML" , totalCount); |
19 | NTES( ".js-joinCount" ).attr( "innerHTML" , TieAnywhere.formatNumber(totalCount.toString(), 3)); |
20 | NTES( ".js-bjoinCount" ).attr( "innerHTML" , TieAnywhere.formatNumber(totalCount.toString(), 3)); |
21 | NTES( ".js-actCount" ).attr( "innerHTML" , TieAnywhere.formatNumber(replyCount.toString(), 3)); |
22 | NTES( ".js-bactCount" ).attr( "innerHTML" , TieAnywhere.formatNumber(replyCount.toString(), 3)); |
24 | wraper: NTES( "#tieArea" ), |
28 | isShowComment: isShowComments, |
34 | tie_ready( function () { |
在该页面下评论数目为:很有可能在data变量的tcount中。即“data.tcount”
其中正常的评论链接格式如下:http://comment.news.163.com/cache/newlist/news_guonei8_bbs/9IISVTCG0001124J_1.html,但是会有乱码,评论之间通过”return tiePage.showPage(4);“
热门评论的链接格式如下:http://comment.news.163.com/data/
boardId/df/
新闻ID_1.html,例如http://comment.news.163.com/data/news_guonei8_bbs/df/9IISVTCG0001124J_1.html,这个评论页面有点不同,它返回的不是一个json文件,而是一个Javascript的变量,变量的值就是“=”号后面的内容,它是一个json,因此要更好地观察具体的内容,你应该新建一个文件(例如comment.json),然后把
“=”之后,“;”之前的内容中复制出来粘贴到comment.json中,接着用浏览器打开comment.json文件。然后你会看到“热门评论”在’hotPosts’中(内容太长了使用Ctrl+f搜索一下hotPosts),而“精彩盖楼”在’buildPosts’中。
评论之间通过”return tiePage.showHotPage(4);“来实现翻页,感觉页面是缓存起来的……一次全部下载完。网易的评论编码好像是UTF-8的,如果乱码那么可以对浏览器选择编码为UTF-8。在实际处理文本内容的时候注意好编码问题。
现在开始分析一下网易新闻评论中各个字段含义,我给出两个例子:
- 前面的数字1表示1楼;
- f是显示的内容,对应分别为“网易XX网友”,用户ID,用户IP,没有用户ID的就显示“网易XX网友”,连“网易XX网友”都没有的就显示IP地址,我猜的;
- v是支持数量;
- u不知道是什么粗略看一眼值全部都是’u’;
- d是当前评论的新闻id;
- t就是发表评论的时间啦;
- b就是评论的内容;
- a就是表示这个楼是不是最后一层楼的;
- p就是上面那个div标签的id;
- n怀疑是网易帐号或者用户名;
- l不知道是什么;
- ip就是ip了。
03 | f: "网易日本手机网友 <span id=9KUDRCJ8 class=cGray>ip:126.255.*.*:</span>" , |
06 | d: "9KUD5BUN00011229" , |
07 | t: "2014-02-13 03:34:08" , |
08 | b: "媽的,這傻逼幹嘛不索取精液流失費?" , |
11 | n: "chinese_cc@163.com" , |
另外一个例子:
03 | f: "网易山东省济南市手机网友 [<a href=''>逗狗儿玩呵呵</a>]: " , |
04 | d: "9KUD5BUN00011229" , |
05 | b: "这么一搞这女的以后还能嫁出去?够阴的。" , |
14 | t: "2014-02-13 04:04:49" , |
16 | tid: "4983565181079566873" |
有没有觉得网易新闻的评论内容中key都很短?而且几乎没有冗余信息。
接下来就是将上述的评论进行格式规范化,假设这个json变量名为js,i为遍历时的下标:
3 | 'user' : js[ 'hotPosts' ][i][ '1' ][ 'n' ], |
4 | 'time' : js[ 'hotPosts' ][i][ '1' ][ 't' ], |
5 | 'content' : js[ 'hotPosts' ][i][ '1' ][ 'b' ] |
要注意的是,上面的’n’不是一定存在的,因为如果有N楼,那么除了最后一层楼外,从1~N-1楼都是没有’n’标签的。呼,网易新闻的也搞掂了。
3.3 新浪新闻
新浪(评论好像是GBK编码)
新浪新闻的URL规则好复杂,推敲了很久才搞明白。
新闻(非专题类)地址格式:http://news.sina.com.cn/
字母c或者w(c表示和中国有关,w表示和中国没有直接关系的世界新闻)/
年-月-日/
小时分钟(
4位数字)及新闻ID的后8位.shtml,例如
http://news.sina.com.cn/c/2014-01-19/021929283928.shtml。
新浪新闻的地址还有一些地址格式有“变种”,例如:http://news.sina.com.cn/c/
sd/2014-01-24/152429336501.shtml,http://news.sina.com.cn/w/p/2014-01-24/154829336676.shtml,还有诸如http://weather.news.sina.com.cn/news/2014/0124/072298232.html和http://mil.news.sina.com.cn/2014-01-24/0839761572.html。
所以综合以上所述,最完整的地址格式应该是:http://
[类别.]news.sina.com.cn/
一堆可能出现的东西/
日期(注意这里的日期格式可能是“年-月-日”也可能是“年/月”)/
小时分钟(4位数字)及新闻ID的后8位.
shtml或者html
有点蛋碎的感觉,不过没事,这些都是一个正则表达式就搞掂的事。
新浪新闻有一个新闻ID和评论通道,这两个东西都比较麻烦,但又很关键,我这里先说获取的方法,下面就知道用途了。以下是
新闻ID获取方法和
评论通道获取方法,在新闻详细页面看到找到以下两行:
1 | <meta name= "comment" content= "kj:2-1-9122947" > |
2 | <meta name= "sudameta" content= "comment_channel:kj;comment_id:2-1-9122947" > |
comment_id同时也是官方所谓的newsid,comment_id的组成是:
channelId-1-
新闻Id后8位,其中中间的1还不知道是什么意思,comment_channel就是评论通道。
最后把得到的评论的格式规范化。假设这个json变量名为js,i为遍历时的下标:
3 | 'user' : js[ 'hot_list' ][i][ 'nick' ], |
4 | 'time' : js[ 'hot_list' ][i][ 'time' ], |
5 | 'content' : js[ 'hot_list' ][i][ 'content' ] |
4 最终格式及补充说明
在新闻格式规范化里面提到了那个格式不是最终的格式,原因就在于实现
http://news.reetsee.com(或者我以后直接叫吹水新闻……)功能的时候,当点击了新闻标题时,评论应该是实时获取的(不应该是爬取新闻一样一开始就使用爬虫下载下来),所以我们需要直接拿到评论的具体内容,不能通过评论页面去获取,而应该直接使用获取新闻评论的json接口(就是上面所有的返回数据格式为json的地址),那么就需要我们根据规则直接拼出接口的URL,这些URL中可能会有日期、新闻ID、评论ID、板块ID等不同的变量,所以我们不妨把它直接放到新闻格式规范化的结果中。为什么不直接等点击链接的时候再到新闻页面获取这些ID?因为这样网速会太慢了。
根据实际需求,腾讯、网易、新浪的新闻保存格式如下:
腾讯:
05 | 'cmtId' : '1004980094' , |
08 | 'title' : '哈尔滨一夜清查酒店洗浴等2700余家' , |
网易:
04 | 'newsId' : '9L2525NG0001124J' , |
05 | 'cmtId' : '9L2525NG0001124J' , |
06 | 'boardId' : 'news_guonei8_bbs' , |
09 | 'title' : '哈尔滨4800余警力一夜清查酒店洗浴等2700余家' , |
新浪:
04 | 'newsId' : '1-1-29471498' , |
05 | 'cmtId' : '1-1-29471498' , |
09 | 'title' : '哈尔滨4800余警力一夜清查2700家酒店洗浴场所' , |
上面的格式其实一看就是有问题的,因为扩展性太差了,这也是我第一次设计囿于时间、经验等造成的,各位自己设计的时候就可以设计得更加好。
这篇东西敲了好久,我想想怎么把文字表述转换一下……使它看起来比较书面一些……然后放到论文中凑凑字数什么的……
过一段时间还会有一篇将毕业设计的设计过程的,那篇也存了草稿很久了,有空再看什么时间弄一弄。
祝大家五一节快乐!放假期间还在看这篇博文的人,都是宅男啊。(
那写这篇东西的我呢!?我了个去)