一 背景
近期有想法,想要拿到指定时间段的新闻/文章信息,简单做个舆情分析。那么最基础的就是先获取文章列表。舆情相关的现成接口有一些,例如 微博的舆情监测平台,里面有比较成熟的 api 提供;阿里云,百度云也都有舆情接口。 不过受限于某些因素,或是费用问题,或是 api 本身能提供的新闻时间范围不符合预期,导致无法直接使用。那么就考虑临时通过 spider 去抓取一些信息,用于支持本次的工作内容。
二 关于舆情检测
舆情监测,是指根据关键词获取舆情信息,包括新闻、论坛、博客、微博、微信、贴吧等。这里补一句,京东云的京东万象,发现是一个不错的 api 聚合入口。以舆情 api 为例,涵盖了多家服务:
各家服务提供方的能力实现,基本也是通过自己抓取和接口合作等方式收集新闻信息,做好渠道覆盖,然后再本地存储后进行舆情分析,并对外提供结果。说起来简单,但涉及检索、模型的部分还是有难度的。
三 信息来源
回归主题。我们要做的第一步是选择一个合适的数据来源,来收集文章。考虑到收集成本,直接用各家搜索引擎/流量平台是个不错的选择,因为作为流量入口,已经帮我们完成了各渠道资源收集的工作。
不过另一方面,各大流量平台都是爬虫齐家,对于各种爬虫策略了如指掌,如果是大批量的抓取是比较容易被发现的。好在我们都只是少量,偶尔的获取信息,而且仅用于学习使用,并不会造成多大的流量影响,所以一般是不会被关注的。有底线,有分寸,真的很重要!
四 内容分析
4.1 搜索示例
正逢最近福建再起疫情,我们就先以这个作为关键词搜索:
结果对应的链接:https://www.baidu.com/s?wd=%E7%A6%8F%E5%BB%BA%20%E7%96%AB%E6%83%85&rsv_spt=1&rsv_iqid=0xff465a7d00029162&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_dl=ib&rsv_sug3=28&rsv_sug1=19&rsv_sug7=101&rsv_sug2=0&rsv_btype=i&inputT=6747&rsv_sug4=11869
4.2 搜索结果内容分析
这里,我们重点分析网页结构,来确认解析方法。
下发的几条搜索结果,都是由:
1、标题(累计发现“6+18”,一文读懂福建疫情现状和传播链),
2、发布时间:(1 天前),
3、内容摘要:【病例详情】莆田市累计发现 6 例确诊、18 例无症状感染者 据莆田市疾控中心介绍,截至 11 日 16 时,此次疫情累计发现 6 例确诊、18 例无症状感染者。福建新增 1 例本土确诊 4 例无症状,均为莆田市报告 9...
4、来源:新京报
组成,这些也是我们要收集的要素。
4.3 页面源码解析
我们页面查看源代码,定为到上面这条新闻的位置如下:
data-click="{
'F':'778717EA',
'F1':'9D73F1E4',
'F2':'4CA6DE6B',
'F3':'54E5263F',
'T':'1631514840',
'y':'FFF5FF4D'
}"
href = "http://www.baidu.com/link?url=q7_vtPksHy_0aWRKZN8tfIsAl3bIFwiqMLAh1keliirFxhui2JPtcElwM4pvYz6_IOYVgaozLiQcXmFK4Gc9mT8i-dt3_6WdlXLeE10L0xO"
target="_blank"
>累计发现“6+18”,一文读懂<em>福建疫情</em>现状和传播链</a></h3><div class="c-row c-gap-top-small"><div class="general_image_pic c-span3" style="position:relative;top:2px;"><a class="c-img c-img3 c-img-radius-large" style="height:85px"
href="http://www.baidu.com/link?url=q7_vtPksHy_0aWRKZN8tfIsAl3bIFwiqMLAh1keliirFxhui2JPtcElwM4pvYz6_IOYVgaozLiQcXmFK4Gc9mT8i-dt3_6WdlXLeE10L0xO"
target="_blank"
><img class="c-img c-img3 c-img-radius-large" src="https://t10.baidu.com/it/u=2742646726,152697636&fm=30&app=106&f=JPEG?w=312&h=208&s=31B6E832CF9241E9146191EF00005021" style="height:85px;" /><span class="c-img-border c-img-radius-large"></span></a></div><div class="c-span9 c-span-last"><div class="c-abstract"><span class=" newTimeFactor_before_abs c-color-gray2 m">1天前 </span>【<em>病例</em>详情】莆田市累计发现6例<em>确诊</em>、18例无症状感染者 据莆田市疾控中心介绍,截至11日16时,此次<em>疫情</em>累计发现6例<em>确诊</em>、18例无症状感染者。<em>福建</em>新增1例本土<em>确诊</em>4例无症状,均为莆田市报告 9...</div><style>.user-avatar {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}</style><div class="f13 c-gap-top-xsmall se_st_footer user-avatar"><a target="_blank" href="http://www.baidu.com/link?url=q7_vtPksHy_0aWRKZN8tfIsAl3bIFwiqMLAh1keliirFxhui2JPtcElwM4pvYz6_IOYVgaozLiQcXmFK4Gc9mT8i-dt3_6WdlXLeE10L0xO" class="c-showurl c-color-gray" style="text-decoration:none;position:relative;"><div class="c-img c-img-circle c-gap-right-xsmall" style="display: inline-block;width: 16px;height: 16px;position: relative;top: 3px;vertical-align:top;"><span class="c-img-border c-img-source-border c-img-radius-large"></span><img src="https://pic.rmb.bdstatic.com/9da74a517eb1befeba93a5f3167cc74b.jpeg"></div><style>.nor-src-icon-v {display: inline-block;width: 10px;height: 10px;border-radius: 100%;position: absolute;left: 7px;bottom: -1px;background-image: url(https://b.bdstatic.com/searchbox/icms/searchbox/img/yellow-v.png);background-size: 10px 10px;}
.nor-src-icon-v.vicon-1 {background-image: url(https://b.bdstatic.com/searchbox/icms/searchbox/img/red-v.png);}
.nor-src-icon-v.vicon-2 {background-image: url(https://b.bdstatic.com/searchbox/icms/searchbox/img/blue-v.png);}
.nor-src-icon-v.vicon-3 {background-image: url(https://b.bdstatic.com/searchbox/icms/searchbox/img/yellow-v.png);}</style><span class="nor-src-icon-v vicon-2"></span>新京报</span></a><div class="c-tools c-gap-left" id="tools_11222397331129245369_10" data-tools='{"title":"累计发现“6+18”,一文读懂福建疫情现状和传播链","url":"http://www.baidu.com/link?url=q7_vtPksHy_0aWRKZN8tfIsAl3bIFwiqMLAh1keliirFxhui2JPtcElwM4pvYz6_IOYVgaozLiQcXmFK4Gc9mT8i-dt3_6WdlXLeE10L0xO"}'><i class="c-icon f13" ></i></div><span class="c-icons-outer"><span class="c-icons-inner"></span></span><style>.snapshoot, .snapshoot:visited {
color: #9195A3!important;
}
.snapshoot:active, .snapshoot:hover {
color: #626675!important;
}</style><a data-click="{'rsv_snapshot':'1'}" href="http://cache.baiducontent.com/c?m=3KZKMrJKhK1otETy33lbReLfsu2eWoaOfZYd2MNWUY3xbKNxMJNNwt_CsOHD6e7Qgf2Tu0GsMgHlSCO1_urn2_JjqYPGu6wMAk4gekije3KTYWOhsyDxmgTxtXJYJJMOij3XKVONqycqZ7hhjK7jNCazerlWVPWh5X0RiBQJlrbX68JcbomnhpiL-nT2Mc-T&p=882a930085cc43fd1cb9d1284e&newp=8b2a970d86cc47f719a28a285f53d836410eed643ac3864e1290c408d23f061d4863e1b923271101d5ce7f6606af4359e1f2337323454df6cc8a871d81edda&s=cfcd208495d565ef&user=baidu&fm=sc&query=%B8%A3%BD%A8+%D2%DF%C7%E9&qid=b3c763fd0003c0d6&p1=10"
target="_blank"
class="m c-gap-left c-color-gray kuaizhao snapshoot">百度快照</a></div></div></div></div>
复制代码
接下来就是处理每个要素的前后标记,并通过对应的前后表情来截取所需的内容。
五 解析源码
5.1 user_agents 设置
#设置多个user_agents,防止百度限制IP
user_agents = ['Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130406 Firefox/23.0', \
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0', \
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533+ \
(KHTML, like Gecko) Element Browser 5.0', \
'IBM WebExplorer /v0.94', 'Galaxy/1.0 [en] (Mac OS X 10.5.6; U; en)', \
'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)', \
'Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14', \
'Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) \
Version/6.0 Mobile/10A5355d Safari/8536.25', \
'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) \
Chrome/28.0.1468.0 Safari/537.36', \
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; TheWorld)']
复制代码
5.2 获取搜索结果的文件内容(html)
这里有一点,pn 代表的是搜索结果的分页,每页的数量是 10,所以传参需要是 0,10,20,...,切记。
def baidu_search(keyword,pn):
p= {'wd': keyword}
res=urllib2.urlopen(("http://www.baidu.com/s?"+urllib.urlencode(p)+"&pn={0}&cl=3&rn=100").format(pn))
html=res.read()
return html
复制代码
5.3 一些工具方法
def getList(regex,text):
arr = []
res = re.findall(regex, text)
if res:
for r in res:
arr.append(r)
return arr
def getMatch(regex,text):
res = re.findall(regex, text)
if res:
return res[0]
return ""
def clearTag(text):
p = re.compile(u'<[^>]+>')
retval = p.sub("",text)
return retval
def write2File(path, content):
f = open(path,'w')
writer = csv.writer(f)
writer.writerow(content)
# 5. 关闭文件
f.close()
复制代码
5.4 解析规则及结果写入文件
def geturl(keyword):
newsList = []
f = open('result-'+keyword+'.csv','w')
writer = csv.writer(f)
for page in range(60):
pn=page*10
html = baidu_search(keyword,pn)
print pn
# write2File('搜索结果-'+str(pn)+'.html', html)
time.sleep(2)
content = unicode(html, 'utf-8','ignore')
itemList = content.split('content_left')
# # print html
for item in itemList:
if item.find('class=\"m c-gap-left c-color-gray')>=0:
linkList = re.findall(r"newTimeFactor_before_abs(.+)font", item)
for link in linkList:
news_date = re.findall(r"span style=\"color: #9195A3;\">(.+)<\/span> - ", link)
title = re.findall(r"\"title\":\"(.+)\",\"url", link)
url = re.findall(r"url\":\"(.+)\"}\'>", link)
source = re.findall(r"class=\"c-showurl\">(.+)<\/span><div", link)
cars = [title[0], news_date[0], source[0], url[0]]
newsList.append(cars)
print title[0]
writer.writerow(cars)
itemList = content.split('newTimeFactor_before_abs c-color-gray2')
i = 0
for link in itemList:
if i == 0:
i=i+1
continue;
if link.find('general_image_pic')>=0:
# print link
news_date = re.findall(r" m\">(.+) </span>", link)
source = re.findall(r".jpeg\"><\/div>(.+)<\/span><\/a><div ", link)
if len(source) <= 0:
source = re.findall(r"<span class=\"nor-src-icon-v vicon-2\"><\/span>(.+)<\/span><\/a><div", link)
title = re.findall(r"\"title\":\"(.+)\",\"url", link)
url = re.findall(r"url\":\"(.+)\"}\'>", link)
if len(source) > 0:
cars = [title[0], news_date[0], source[0], url[0]]
newsList.append(cars)
print title[0]
writer.writerow(cars)
i=i+1
# 5. 关闭文件
f.close()
time.sleep(5)
复制代码
5.5 执行入口
if __name__=='__main__':
arr = ['检索词1 1','检索词2 2']
for keyword in arr:
geturl(keyword)
复制代码
六 总结
至此,一个尝试性的 spider 编写完毕。如果想获取更多代码或保持技术上的沟通交流,可以关注公众号【程序员架构进阶】获取。另外再啰嗦一句,一定是只学习使用,不可大批量执行等类似攻击的行为。共勉。
评论