腾讯、网易、新浪新闻网站爬虫编写记录及评论格式分析

4.43 avg. rating (89% score) - 7 votes
转载请注明: 吹水小镇 | reetsee.com
原文链接地址: http://blog.reetsee.com/archives/237

0 前言

先说说看这篇博客你能知道什么:1 腾讯、网易、新浪不同新闻的地址格式以及评论内容的地址格式(返回数据为json的异步接口);2 一些比较通用的设计方法,对软件设计的菜鸟可能有帮助;

之前也说了要写这篇博客,现在终于写出来了。我的毕业设计的指导老师说毕设论文的字数不够……所以我决定把这些本不应该出现在论文中的实现细节凑到论文中。至于下面说到的东西要解决什么问题,各位可以先看看这个网站(我毕设的初步结果,目前还在优化中,包括代码结构还有UI设计):http://news.reetsee.com/

凡是这篇博文中出现超链接的地方,可以放心点击,新的页面会在新标签中打开而不会直接在当前的标签打开。

这个网站要实现以下功能:从腾讯新闻、网易新闻、新浪新闻中(当然以后可能会更多其它新闻网站)通过代码自动分析出哪些新闻内容是相似的,然后把相似的内容组织到一起,例如三个网站都有“北京成功申奥”这样的新闻,这个网站会自动把三条新闻归到一起,然后把三个新闻网站的热门评论都下载下来,按照时间排序,最后通过代码计算出一段“评论概括”,因为有的人很懒,看新闻基本就是看了标题然后看评论,看评论可能只看热门评论,看热门评论可能还看那种被顶得最多的,所以我就这么帮下这些懒人了……哈哈哈。

网站打开得有点慢,这个是因为我的代码写得不够好,在百度也看到很多牛逼的技术内容,回头看看这个毕设的各种设计,觉得有点丢脸,迟点重构····目前先凑合着用。咳咳,跑题了,这个网站的所有内容可以说都是通过爬虫抓取下来了,我的工作只不过是将爬虫获取的内容进行了组织然后重新展现。

这篇博客的内容仅仅是说一下爬虫是怎么写的,完全不会涉及分析新闻相似的算法是怎么样的以及对热门评论进行概括的算法是怎么样的。

那么下面开始。

20161128 注:网易新闻的接口经历过不少变动,在看到下面网易新闻结局的部分可以回头看看这里。多了一个product key的概念,以及board id的获取已经不能直接从html中取得,新闻标题的html标签也变化了。代码已经做了相应的改动,详见这两个commit:修复网易新闻获取规则修复网易新闻标题位置。(感觉网易新闻的这个改动是要将新闻作为一个接入产品,底层的实际数据做成开放接口了?)

1 新闻格式规范化

我在同学介绍下选择了Python的Scrapy爬虫框架进行爬虫编写(最近我自己用PHP写了个爬虫框架Phpfetcher,可以参见这里:http://blog.reetsee.com/archives/366)。要在自己的网站上展示新闻内容,就应该将下载好的新闻按照统一的格式处理好,这样前端(网页端)才能够方便地处理、展示。一篇新闻有以下几个需要关注的地方:

  1. 新闻标题
  2. 新闻正文
  3. 新闻时间

 由于要知道新闻的来源以及对应的评论,所以加上这两项:4. 新闻来源,5. 新闻评论地址。

那么最终在我这里,一篇处理后的新闻格式应该是这样的(这里使用类似json的格式表示,“[]”表示一个数组,“{}”表示一个字典):

{
	'source'   : '来源网站',
	'date'     : '时间(长度8位,如20140501)', 
	'contents' : {
			'link'    : '新闻详细内容页面的地址', 
			'title'   : '新闻标题',
			'passage' : '新闻正文',
		     },
	'comments' : {
			'link' : '新闻对应的评论页面地址',
		     },
}

如果有人问既然已经有了新闻的地址页面,为什么还要将新闻标题、新闻正文这些内容保存到本地呢?因为要在本地对新闻进行分类,就必须将这些内容下载下来。

上面的格式只是一个初步的统一格式,最终的格式相比这个可能会有小变化,这个后面再说。

2 评论格式规范化

要在我的网站对评论进行展示,就要有统一的格式,通常评论的要素包括三个:

  1. 用户名
  2. 评论时间
  3. 评论内容

 由于我要标注评论的来源,所以再加一个:4. 评论来源,那么最终被我处理过的评论格式如下:

{
	'source' : '来自哪个新闻网站',
	'user' : '用户名',
	'time' : '10位长度的时间戳', //转换成时间戳是为了方便以后排序
	'content' : '评论内容'
}

那么最终重新按照时间排序后的评论列表格式应该是像下面这样的:

[
	{
		'source' : '',
		'user' : '',
		'time' : '',
		'content' : ''
	},
	{
		'source' : '',
		'user' : '',
		'time' : '',
		'content' : ''
	},
	{
		'source' : '',
		'user' : '',
		'time' : '',
		'content' : ''
	},

	...
]

这里先规范好最终的评论格式,下面针对评论部分的讲解设计就有头有据了。

另外就是评论并不需要爬虫下载!因为评论是实时更新的,不像新闻,基本上发布了就不怎么变化了。因为评论的内容是在用户点击某条新闻后才通过HTTP请求获取的。

3 URL规则分析

3.1 腾讯新闻

其实整个分析下来,我觉得腾讯的URL地址格式是最容易弄清楚的,对于下面的内容,打了黄色背景色的是一个分析说明,其中用了红色字体的代表这个地方是依据新闻的不同而变化的,聪明的你们一定一看就知道是什么意思了。在看下面的内容时,可以自己把这些URL敲到地址栏中尝试一下,其次是使用CHROME或者百度浏览器的同学,强烈建议安装“FeHelper”这个插件,地址是:https://chrome.google.com/webstore/detail/web%E5%89%8D%E7%AB%AF%E5%8A%A9%E6%89%8Bfehelper/pkgccpejnmalmdinmhkkfafefagiiiad?hl=zh-CN,这个东西的作用是能够直接将JSON格式的内容美化成很漂亮的非常容易读到的内容,例如这样:
fehelper
这个是其中一个功能,还有很多非常赞的功能。
回到正文。
新闻(非专题类)地址格式   :http://news.qq.com/a/8位日期/新闻ID.htm,例如:http://news.qq.com/a/20140113/012246.htm
新闻页面获取评论数量的方法:http://coral.qq.com/article/评论页ID(即cmt_id)/commentnum?callback=_cbSum&source=1&t=随机数(怀疑是时间戳,但是好像没什么用),例如:http://coral.qq.com/article/1004703995/commentnum?callback=_cbSum&source=1&t=0,实际上这个用不到。
新闻的所有评论页面地址      :http://coral.qq.com/评论ID(即cmt_id,例如:http://coral.qq.com/1004703995
其中正常的评论链接格式如下:http://coral.qq.com/article/评论页ID(即cmt_id)/comment?commentid=起始ID&reqnum=显示数目&tag=&callback=mainComment&_=时间戳+3位随机整数(共10+3=13位)http://coral.qq.com/article/1004703995/comment?commentid=0&reqnum=20&tag=&callback=mainComment&_=1389623278900。实际上这个用不到。
热门评论的链接格式如下      :http://coral.qq.com/article/评论页ID(即cmt_id)/hotcomment?reqnum=显示数目&callback=myHotcommentList&_=时间戳+3位随机整数(共10+3=13位)http://coral.qq.com/article/1004703995/hotcomment?reqnum=10&callback=myHotcommentList&_=1389617814425
要注意的是,评论页ID是大于10^9的;新闻ID不是一个数字,注意真的不是一个数字!而是一个只包含数字的字符串,例如它可能是“000123”。
现在开始分析一下腾讯新闻评论中的字段,比起网易新闻的简直是太臃肿了,那么就直接说关心的内容了(请直接点击上面热门评论的那条URL、或者复制到你的地址栏,回车后查看结果,与下面的内容比对):
  1. targetid就是新闻的id;
  2. time就是时间戳,有了这个可以转换成公元时间;
  3. content就是回复的内容(这位网友真是热心回复这么多);
  4. up就是人家给的赞的数量;
  5. userinfo中的nick就是用户名了,后面竟然还有对应的腾讯微博的用户信息。
{
	id: "5828439023791190273",
	targetid: 1004703995,
	parent: "0",
	replyuser: "",
	replyuserid: 0,
	timeDifference: "01月13日 18:15:50",
	time: "1389608150",
	content: "很高兴看到中央军委日前印发《关于军队贯彻落实〈党政机关厉行节约反对浪费条例〉的措施》,规定今后所有公务用车采购国产自主品牌,其实不光是汽车,像电脑、打印机、扫描仪、复印机、服务器、网络设备、软件等产品更要带头采购国产自主品牌,防止军队内部机密资料遭受国外网络黑客攻击!希望中央军委、中国海陆空军队能够切实担负起捍卫国土、捍卫钓鱼岛的职责!其实中国的部队,大部分军官素质是好的,但也有相当一部分军官也十分腐败,作风腐化堕落,为人霸道欺负新兵,道德品质极差;艰苦奋斗、勤俭建军的思想有所淡化;革命意志、进取精神有所退化;铺张浪费、大手大脚现象有所抬头。加强军队的反腐倡廉建设对于巩固党的执政地位、树立中国军队的新形象、提升国防战斗力十分重要。要保卫好祖国国土完整,加强军队作风建设和反腐倡廉建设责任重大。“物必自腐,而后虫之”,如果任由各种腐败作风在军队系统漫延,将使中国军队的整体战斗力、中国军官的整体政治素质大大下降,后果不堪设想!希望中央军委一定要在全军大力开展创先争优活动,加强中国军人综合素质建设与作风建设,全面推广党风廉政建设巡视检查制度,大力清除军队内部的腐败分子,大力整顿军队内部的“吃喝玩乐嫖赌、卖官鬻爵收受贿赂违规提拔干部”等各类不正之风,营造“勤于学习、善于学习、钻研技术、廉洁从业”的良好氛围,铸造一支英勇善战、战斗力凝聚力号召力超强的中国军队!同时中国军队应该坚持人性化细节化管理,对于长期夫妻两地分居的军官、军人要免费发放性慰器,防止他们流入社会进入嫖娼卖淫场所影响中国军队形象!希望中国能够集国家和中华民族的坚强意志,大力加强自主创新型国家建设,努力攻克在大型民用飞机、军用飞机、导弹系统、航空母舰等制约国家核心技术的关键高端产业领域,早日使我国的民用与军用飞机、导弹、航空母舰早日上市,彻底摆脱对欧洲、美国、日本在先进技术上的制约,成为一个装备制造强国!中国不能搞、不会搞军事扩张但也绝不能太懦弱,一定要夯实军事装备,提升军队战斗力,保护好国土、海域的安全,捍卫民族尊严!",
	up: "91",
	rep: "0",
	type: "2",
	hotscale: "3",
	checktype: "2",
	checkstatus: "1",
	isdeleted: "0",
	tagself: "",
	taghost: "",
	source: "1",
	userinfo: {
		userid: "21059616",
		uidex: "ec52a391823814524e8446efa3bd6a48d9",
		nick: "炎黄子孙中国梦",
		head: "http://q1.qlogo.cn/g?b=qq&k=ACz0AuPMwiaSfHTmIGWbIOw&s=40&t=0",
		gender: "1",
		viptype: "0",
		mediaid: 0,
		region: "中国:安徽:宣城",
		thirdlogin: 0,
		wbuserinfo: {
			name: "cjppjc17",
			nick: "炎黄子孙中国梦",
			url: "",
			vip: 0,
			ep: 0,
			brief: "",
			identification: "",
			intro: "",
			liveaddr: {
				country: "1",
				province: "34",
				city: "18",
				area: ""
			},
			level: 0,
			classify: ""
		},
		commentnum: "283",
		commentednum: "168",
		upnum: "2108"
	}
},

还记得在“评论规范化”中定的格式吗?现在我们就从上面的json格式找到一个将其规范化的方法,假设热门评论连接中返回的json格式的变量名为js,i为遍历时的下标,那么用下面这个方法进行评论格式的规范化

{
	'source' : 'tencent',
	'user' : js['data']['commentid'][i]['userinfo']['nick'],
	'time' : js['data']['commentid'][i]['time'], //原格式就是10位时间戳了不用转换
	'content' : js['data']['commentid'][i]['content']
}

 

腾讯新闻的算是搞掂了。

3.2 网易新闻

新闻(非专题类)地址格式   :http://news.163.com/年份/日期(四位)/数字/新闻ID.html,例如http://news.163.com/14/0114/19/9IISVTCG0001124J.html
新闻页面获取评论数量的方法:查找”totalCount“就是评论数目,新闻ID就是”threadId“,讨论版面就是”boardId“,这个js是inline的,直接就放到网页中了:
<script type="text/javascript">
    if (typeof isForceShowComment != "undefined") {
        isShowComments = isForceShowComment;
    };
    function tieInit() {
        tie_load({
                    urs: "http://img1.cache.netease.com/utf8/microblog/urs/urs1.0.3.js",
                    tie: "http://img1.cache.netease.com/utf8/tie/tieanywhere2.6.6-min.js"
                },
                function() {
                    var replyCount = 10068,
                            totalCount = 59215,
                            threadId = "9IISVTCG0001124J",
                            boardId = "news_guonei8_bbs",
                            host = tieChannel,
                            tId = tId;
                    NTES(".js-tielink").attr("href", "http://comment." + host + ".163.com/" + boardId + "/" + threadId + ".html")
                    NTES(".js-tiecount").attr("innerHTML", totalCount);
                    NTES(".js-joinCount").attr("innerHTML", TieAnywhere.formatNumber(totalCount.toString(), 3));
                    NTES(".js-bjoinCount").attr("innerHTML", TieAnywhere.formatNumber(totalCount.toString(), 3));
                    NTES(".js-actCount").attr("innerHTML", TieAnywhere.formatNumber(replyCount.toString(), 3));
                    NTES(".js-bactCount").attr("innerHTML", TieAnywhere.formatNumber(replyCount.toString(), 3));
                    new TieAnywhere.Tie({
                        wraper: NTES("#tieArea"),
                        threadId: threadId,
                        boardId: boardId,
                        host: host,
                        isShowComment: isShowComments,
                        isStrict: isStrict,
                        tId: tId
                    });
                })
    };
    tie_ready(function() {
        if (!window.NTES) {
            tie_load({ lib: "http://img1.cache.netease.com/cnews/js/ntes_jslib_1.x.js" }, function() {
                tieInit();
            }, "GBK")
        } else {
            tieInit();
        };
    });
</script>
<!--tie end-->

 

新闻的所有评论页面地址:http://comment.news.163.com/boardId/新闻ID.html,例如http://comment.news.163.com/news_guonei8_bbs/9IISVTCG0001124J.html。关于boardId及新闻ID,请参见上面一项。
在该页面下评论数目为:很有可能在data变量的tcount中。即“data.tcount”
其中正常的评论链接格式如下:http://comment.news.163.com/cache/newlist/news_guonei8_bbs/9IISVTCG0001124J_1.html,但是会有乱码,评论之间通过”return tiePage.showPage(4);
热门评论的链接格式如下
20160415注:我发现网易新闻大改版了,标题的html标签不同了,而热门评论的Ajax接口也换了,所以我在这里也更新之前博客写的内容。
http://comment.news.163.com/api/v1/products/a2869674571f77b5a0867c3d71db5856/threads/新闻ID/comments/hotTopList?offset=从第几条开始(通常为0)&limit=返回数量上限&showLevelThreshold=72&headLimit=1&tailLimit=2&callback=getData&ibc=newspc,URL里面的其它参数就不做详细分析了,上面的格式的一个例子如下:http://comment.news.163.com/api/v1/products/a2869674571f77b5a0867c3d71db5856/threads/BKMGMST50001124J/comments/hotTopList?offset=0&limit=40&showLevelThreshold=72&headLimit=1&tailLimit=2&callback=getData&ibc=newspc,这个评论页面有点不同,它返回的不是一个json文件,而是一个Javascript的变量(JSONP回调),评论内容就在花括号内,它是一个json,因此要更好地观察具体的内容,你应该新建一个文件(例如comment.json),然后把花括号“{}”之间的内容(包括花括号本身)复制出来粘贴到comment.json中,接着用浏览器打开comment.json文件。然后你会看到“热门评论”在’comments’字段中。评论之间通过”return tiePage.showHotPage(4);“来实现翻页,感觉页面是缓存起来的……一次全部下载完。编码是UTF-8的,如果乱码那么可以对浏览器选择编码为UTF-8。在实际处理文本内容的时候注意好编码问题。
现在开始分析一下网易新闻评论中各个字段含义:
前面的数字表示评论id;
  • 里面的部分buildLevel表示盖楼数(应该是);
  • content表示评论内容;
  • createTime就是评论发表时间;
  • postId就是新闻id与评论id拼起来后的字符串;
  • user就是用户相关的信息,通常我们关心里面的nickname即用户名称即可
  • vote就是被顶的次数
931804338: {
    against: 0,
    anonymous: false,
    buildLevel: 1,
    commentId: 931804338,
    content: "必须的!猪肉都涨了30%以上!",
    createTime: "2016-04-15 10:48:13",
    favCount: 0,
    ip: "219.137.*.*",
    isDel: false,
    postId: "BKMGMST50001124J_931804338",
    shareCount: 0,
    source: "wb",
    user: {
        avatar: "http://img2.ph.126.net/aVsKiVqjtytuhlIaVBWLPw==/656118170730205310.jpg",
        id: "ZmFyZXdlbGxfdWNrQDE2My5jb20=",
        label: "[{"endTime":"1457574655664","startTime":"1457488255663","tagKey":"100"},{"endTime":"1457523423909","startTime":"1457437023908","tagKey":"101"},{"endTime":"1457173148975","startTime":"1457086748974","tagKey":"102"},{"endTime":"1454603975126","startTime":"1454517575126","tagKey":"103"},{"endTime":"1456968812620","startTime":"1456882412619","tagKey":"104"},{"endTime":"1457074346651","startTime":"1456987946651","tagKey":"105"}]",
        location: "广东省广州市增城市",
        nickname: "见朕骑妓的時刻到了",
        userId: 58444404
    },  
    vote: 51
}
有没有觉得网易新闻的评论内容中key都很短?而且几乎没有冗余信息。
接下来就是将上述的评论进行格式规范化,假设这个json变量名为js,i为遍历时的下标:
{
	'source' : 'netease',
	'user' : js['comments'][i]['user']['nickname'],
	'time' : js['comments'][i]['createTime'], //原格式“%Y-%m-%d %H:%M:%S”,要转换成10位长度的时间戳
	'content' : js['comments'][i]['content']
}

 

要注意的是,上面的’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获取方法和评论通道获取方法,在新闻详细页面看到找到以下两行:
<meta name="comment" content="kj:2-1-9122947">
<meta name="sudameta" content="comment_channel:kj;comment_id:2-1-9122947">

 

comment_id同时也是官方所谓的newsid,comment_id的组成是:channelId-1-新闻Id后8位,其中中间的1还不知道是什么意思,comment_channel就是评论通道。
新闻页面获取评论的方法:http://comment5.news.sina.com.cn/page/info?format=格式(可选json,js)&channel=板块(通常是2个字母)&newsid=评论ID(即上面的comment_id)&group=0(默认为0)&compress=1&ie=gbk&oe=gbk&page=第几页(数字越大评论越旧)&page_size=缓存的评论数(并非展示的评论数)&jsvar=requestId_貌似是个随机整数(非常不确定),例如http://comment5.news.sina.com.cn/page/info?format=json&channel=gn&newsid=1-1-29283928&group=0&compress=1&ie=gbk&oe=gbk&page=1&page_size=100&jsvar=requestId_24959748,返回的内容是所有的评论,热门评论在“hot_list”中,关联的新闻信息在“news”中,正常的评论在“cmtlist”中,另外包含一些在“replydict”中的东西,不知道是什么。其中评论数目在“count”的“show”中
对应的所有评论页面地址:http://comment5.news.sina.com.cn/comment/skin/default.html?channel=板块(见上面的解释)&newsid=评论IDhttp://comment5.news.sina.com.cn/comment/skin/default.html?channel=gn&newsid=1-1-29283928
最后把得到的评论的格式规范化。假设这个json变量名为js,i为遍历时的下标:
{
	'source' : 'sina',
	'user' : js['hot_list'][i]['nick'],
	'time' : js['hot_list'][i]['time'], //原格式“%Y-%m-%d %H:%M:%S”,要转换为10位时间戳
	'content' : js['hot_list'][i]['content'] 
}

 

4 最终格式及补充说明

在新闻格式规范化里面提到了那个格式不是最终的格式,原因就在于实现http://news.reetsee.com(或者我以后直接叫吹水新闻……)功能的时候,当点击了新闻标题时,评论应该是实时获取的(不应该是爬取新闻一样一开始就使用爬虫下载下来),所以我们需要直接拿到评论的具体内容,不能通过评论页面去获取,而应该直接使用获取新闻评论的json接口(就是上面所有的返回数据格式为json的地址),那么就需要我们根据规则直接拼出接口的URL,这些URL中可能会有日期、新闻ID、评论ID、板块ID等不同的变量,所以我们不妨把它直接放到新闻格式规范化的结果中。为什么不直接等点击链接的时候再到新闻页面获取这些ID?因为这样网速会太慢了。
根据实际需求,腾讯、网易、新浪的新闻保存格式如下:
腾讯
{
	'source'   : 'tencent', 
	'date'     : '20140214', 
	'newsId'   : '015412', 
	'cmtId'    : '1004980094',
	'contents' : {
			'link'   : 'http://news.qq.com/a/20140214/015412.htm',
			'title'  : '哈尔滨一夜清查酒店洗浴等2700余家',
			'passage': '正文内容'
		     },
	'comments' : {
			'link' : 'http://coral.qq.com/1004980094',
		     }
}

 

网易

{
	'source'   : 'netease', 
	'date'     : '20140214', 
	'newsId'   : '9L2525NG0001124J', 
	'cmtId'    : '9L2525NG0001124J',
	'boardId'  : 'news_guonei8_bbs',
	'contents' : {
			'link'    : 'http://news.163.com/14/0214/14/9L2525NG0001124J.html',
			'title'   : '哈尔滨4800余警力一夜清查酒店洗浴等2700余家',
			'passage' : '正文内容'
		     },
	'comments' : {
			'link' : 'http://comment.news.163.com/news_guonei8_bbs/9L2525NG0001124J.html',
		     },
}

新浪

{
	'source'    : 'sina', 
	'date'      : '20140214', 
	'newsId'    : '1-1-29471498', 
	'cmtId'     : '1-1-29471498',
	'channelId' : 'gn',
	'contents'  : {
			'link'    : 'http://news.sina.com.cn/c/2014-02-14/142829471498.shtml',
			'title'   : '哈尔滨4800余警力一夜清查2700家酒店洗浴场所',
			'passage' : '正文内容',
		      },
	'comments'  : {
			'link' : 'http://comment5.news.sina.com.cn/comment/skin/default.html?channel=gn&newsid=1-1-29471498',
		      },
}

 

上面的格式其实一看就是有问题的,因为扩展性太差了,这也是我第一次设计囿于时间、经验等造成的,各位自己设计的时候就可以设计得更加好。
这篇东西敲了好久,我想想怎么把文字表述转换一下……使它看起来比较书面一些……然后放到论文中凑凑字数什么的……
过一段时间还会有一篇将毕业设计的设计过程的,那篇也存了草稿很久了,有空再看什么时间弄一弄。
祝大家五一节快乐!放假期间还在看这篇博文的人,都是宅男啊。(那写这篇东西的我呢!?我了个去)

50 条思考于 “腾讯、网易、新浪新闻网站爬虫编写记录及评论格式分析

      1. 新手

        不好意思,刚才只看到下面那条,刚看到这里您已经回答过了。我是新手,能否请您讲的再详细一点?

        我测试了把“&reqnum=……”后面的都删掉,都不影响结果。但是似乎每次reqnum最多是50条,所以要把评论都弄下来,就必须要这个commentid?是这样吗?

        多谢了!

      2. 新手

        我再说详细一点啊
        比如我要抓的评论地址是http://coral.qq.com/1144188125
        我用f12先得到前10个评论链接地址
        http://coral.qq.com/article/1144188125/comment?commentid=0&reqnum=10&tag=&callback=mainComment&_=1429600427084
        然后用”加载更多“,又得到20个评论的连接地址
        http://coral.qq.com/article/1144188125/comment?commentid=5996156889457034086&reqnum=20&tag=&callback=mainComment&_=1429600427088

        第二个里面commentid=5996156889457034086。我在看代码是,
        “reqnum”:20,”retnum”:20,”maxid”:”5996178882751433678″,”first”:”5996154213122001017″,”last”:”5996118518105983034″
        这几个数和url里的都不一样,没关系?

        实在搞不明白,麻烦您指教。谢谢啦

        1. fanfank 文章作者

          我大概明白你的意思了。其实两个comment_id不是一个东西。我在正文中提到的comment_id,实际是指关联到某个新闻网站中的某条新闻的评论页面的id。
          而你的例子中的commentid,是腾讯在内部标识一条唯一评论的id。
          就是说,一个是评论页的id,一个是具体评论所对应的id。而我所抓取的那个实际是评论页的id。
          评论页的id有可能与新闻id一致,但也有可能不一致(利润腾讯的新闻id与评论也id就是不一样的)

          1. 新手

            fanfank您好
            是的,我就是这个意思。我理解楼下这个patty好像问的也是这个,就是您写的“commentid=起始ID”里的“起始ID”从哪里获得。虽然默认的是0,但是通过这个最多只能获得50条。而我要继续往后爬,是不是就必须得要能给出下一个50条(默认是20条)的起始ID,但我没有能够找出规律。

            我看到网上有收费软件,能够实现对腾讯评论的全下载功能,所以感觉应该是可以获得的:(

  1. patty

    您好!请问您知不知道“http://coral.qq.com/article/评论页ID(即cmt_id)/comment?commentid=起始ID&reqnum=显示数目。。。”中的“commentid=起始ID”该怎么得到?

        1. fanfank 文章作者

          不好意思,我今天才发现原来系统把你发送的信息识别为有害信息,所以我一直没留意到待处理评论里面还有你的评论。不过现在你的问题好像得到解答了,那就OK

        1. patty

          commentid默认从0开始,然后当你点击“加载更多”时,下一个commentid=上一个(也就是commentid = 0的那个页面中的)last的值

      1. 高一平

        可以考虑开一个api,大家可以直接获取新闻及内容。这样就省去很多事情了,内容用txt存到云上,这样服务器效率就高了,一个简单的host就能完成服务,您觉得呢?

        1. fanfank 文章作者

          这个接口在新闻详情页,需要自己找一下,因为不想公开这个。外部调用太多的话可能造成我的网站对网易等几个新闻评论接口的异常访问而导致被封或者被使用粒度控制策略。

      1. jack

        对于网易的专题新闻(http://j.news.163.com/docs/10/2015051110/APB1TTFR00011229.html),在源代码中找不到boardId,如何能获得boaidid呢,

        1. fanfank 文章作者

          你说的这条专题实际上原文地址是这个:
          (http://news.163.com/15/0511/10/APB1TTFR00011229.html),
          里面是有boardId的。所以专题类型新闻对应的页面,你可以通过专题的URL反推出它的原新闻地址,例如专题的URL里面后边的新闻ID以及时间部分都是和原文有关联的
          当然这种做法相对迂回一点,但是如果你专门要抓专题类新闻的话,这个实际是个不错的选择,另外如果你要抓专题类新闻里某个专题下的历史新闻,可以分析一下“新闻回顾”部分的HTML标签有什么特征然后用特殊逻辑进行抓取

  2. jack

    腾讯新闻评论(http://coral.qq.com/article/评论页ID(即cmt_id)/comment?commentid=起始ID&reqnum=显示数目)起始ID怎么获得?

    1. fanfank 文章作者

      后面的参数可以不填,这样也是能返回结果的,返回结果里有评论的内容及id,如果你要做翻页功能,那么就使用返回结果中的最后一个评论的id

  3. 刘一道

    非常幸运看到楼主一年前的文章,受益匪浅!
    有个问题请教楼主,sina新闻评论的网址pattern,就是http://comment5.news.sina.com.cn。。。。。 楼主是如何分析得到的?我看了sina新闻页的源代码,没有发现这个链接。请楼主赐教,不胜感谢。

    1. fanfank 文章作者

      使用Chrome/Firefox浏览器,右键空白的地方选择『审查元素』之类的,然后会弹出一个类似debug窗口一样的东西,选择『网络』,里面会看到所有的动态请求,就是像下面这样:
      inspect

  4. 赵思琪abc

    就是有个疑问,关于 “通过代码自动分析出哪些新闻内容是相似的,然后把相似的内容组织到一起,例如三个网站都有“北京成功申奥”这样的新闻,这个网站会自动把三条新闻归到一起,然后把三个新闻网站的热门评论都下载下来,按照时间排序,最后通过代码计算出一段“评论概括” 的疑问不知道博主是否方便透露一下相关的算法呢?

    1. fanfank 文章作者

      我用的算法很简单,这两部分的代码都在这个下面:https://github.com/fanfank/news-combinator/tree/master/chnsegmt

      我大致说一下思路,对相似文章的分类可以先用中文分词(例如结巴分词)把每篇文章打散成词语,然后取每篇文章TOP10或者TOP20的词语并统计出现次数,当然你需要把一些语气词等去掉,保留名词和动词是比较好的。

      然后每篇文章起始就能使用自己的这组词语,把它看成一个向量,然后去计算和其它文章的向量夹角(余弦相似度),你可以定一个值,例如超过0.75的你可以认为两篇文章能归到一起。

      评论的概括也比较简单,你把所有评论首尾相接,看成一篇文章,然后分词,取出TOP 20的词语,然后去看每一条评论,对评论进行分句,句子中出现TOP 20词语越多的,权重越大(权重怎么设你可以自己决定),然后把权重最大的几条句子取出来就行

  5. 石啸

    我在执行
    python categorize.py -o G:\undergarduate_finalexam\final_test\news-combinator\result G:\undergarduate_finalexam\final_test\news-combinator\crawler\docs\tencent 的时候
    结果是
    usage: python categorize.py -k number_of_tags -o output_directory source_directories …

    请问我应该怎么修改?

      1. 石啸

        categorize.py 是在你的吹水新闻demo1.0中
        (https://github.com/fanfank/news-combinator/tree/master/chnsegmt)
        我在run.py中加了-k 10还是显示的这个
        (usage: python categorize.py -k number_of_tags -o output_directory source_directories )

    1. fanfank 文章作者

      当时代码开放出来基本没有考虑过别人使用的问题,所以现在不清楚会不会有一些问题,当时我的开发都是在Linux下做的,Widnows的环境没有测试过。
      从代码来看,能打出usage的情况只有一个,就是-o参数没有指定或者输入参数少于两个,不过从你给的命令来看也不会出现这种情况,你那边如果方便可以考虑下切换到Linux里面进行开发试试。
      不行的话可以参照代码进行适当的重写

  6. lycoris

    最近也是在做相关的爬虫毕设,这篇文章,让我受益匪浅,非常感谢。我还有个问题想请教下,我在持久化新闻的时候,将图片src的链接替换成本地地址,然后将图片保存到本地。到后面数据展示才发现有个问题,img标签src无法加载本地图片,查资料说是为了安全考虑,无法加载本地资源。我的爬虫和展示是不同的模块,用相对路径也不好处理。直接存原始图片数据到数据库的话,这样数据量会不会太大了?查资料说img对base64图片数据加载之后不会缓存。请问有什么好的方法处理吗?

    1. fanfank 文章作者

      可以用CDN来存,七牛或者阿里云都有对应的产品(用对象存储产品也可以)。他们都会有对应语言的API,例如你有一个图片的src地址,然后调用它们的接口它们会自己帮你下载图片,然后返回给你一个CDN对应的URL或者获取这个图片的URL。
      如果不想用CDN,可以下载到本地,然后让Nginx或者Apache能够通过URL访问到这些图片就行,你的展示页面里面将src设置成这个能访问到图片的URL就行。
      从你的描述来看应该量不大,自己保存到本地然后通过URL访问自己的图片就行,也就是推荐你用第二种方法。

      1. lycoris

        非常感谢,第二种是比较简便且实用的,可以很好地解决我当前的问题。有人还向我提供了一个方案,使用fastdfs文件系统,这个应该是跟第一种方法类似的吧?对此我还是蛮感兴趣的,有时间可以学习下。最后,再次感谢。

发表评论

电子邮件地址不会被公开。 必填项已用*标注