写点什么

一次爬虫的编写尝试

发布于: 1 小时前
一次爬虫的编写尝试

一 背景

近期有想法,想要拿到指定时间段的新闻/文章信息,简单做个舆情分析。那么最基础的就是先获取文章列表。舆情相关的现成接口有一些,例如 微博的舆情监测平台,里面有比较成熟的 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天前&nbsp;</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" >&#xe62b;</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,防止百度限制IPuser_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 arrdef 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 retvaldef 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>&nbsp;-&nbsp;", 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\">(.+)&nbsp;</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 编写完毕。如果想获取更多代码或保持技术上的沟通交流,可以关注公众号【程序员架构进阶】获取。另外再啰嗦一句,一定是只学习使用,不可大批量执行等类似攻击的行为。共勉。

发布于: 1 小时前阅读数: 3
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
一次爬虫的编写尝试