一、简述
这篇文章我们介绍获取网易抗疫新闻版块数据并对其进行保存。
二、
第一篇博客中我们已经通过抓包的方式获取了网易新闻(移动版)中的抗疫版块新闻接口:
https://gw.m.163.com/nc/api/v1/feed/static/h5-normal-list?start=0&size=10&tid=T1579658657288
我们在python中进行如下请求:
api = 'https://gw.m.163.com/nc/api/v1/feed/static/h5-normal-list'
params = {
'start': 0, # 开始索引
'size': 10, # 请求条数
'tid': 'T1579658657288' # 版块id(这里指抗疫版块)
}
req = requests.get(api, params)
print(req.text)
返回如下: 也就是说我们请求到数据了。
接下来看一下数据的格式:
'data'下的数据有两个字段,‘items’保存了请求得到的新闻,‘wap_pluginfo’下保存的是抗疫版块下的额外信息,如下:
我们暂时只关心‘items’字段下的内容,因为‘wap_pluginfo’下只保存这三个url且不变,故我们暂时不关心。
注:这里在发出请求时发现,size必须为10以及10的倍数,否则将请求不到任何数据,大概因为移动端在网易每次刷新时是请求新的10条数据。
这里我先请求了10条数据,但item中共有12项,看一下有什么不同:
首先回到网页分析请求得到的新闻在哪,首先是第一条,它位于页面的最上方,比如今天:
另外第二三条数据进分析应该是当日疫情数据:
后面九条数据则是显示在页面下方的新闻,因此新闻条数为10条,且附带两条疫情数据。
那接下来我们就只需要分析获取的第1条数据和第4条开始的数据即可。
打印其键值:
除去第二三条,我们发现还有一条数据的键值有些不同,那就是第四条,而第四条数据代表的是页面下方多条新闻的第一条,该条为专题。
因为我们只需要新闻 ,所以接下来我们关注每一条新闻含有哪些信息。
首先我们看头条新闻的键有哪些:
['specialID', 'unfoldMode', 'votecount', 'upTimes', 'downTimes', 'replyCount', 'commentStatus', 'postid', 'boardid', 'picCount', 'recommendSources', 'subscribedMotifs', 'skipType', 'skipID', 'sourceId', 'source', 'mtime', 'topicid', 'topic_background', 'imgsrc', 'extraShowFields', 'hasHead', 'order', 'priority', 'quality', 'ename', 'hasIcon', 'region', 'cid', 'template', 'riskLevel', 'lmodify', 'title', 'hasImg', 'digest', 'alias', 'hasAD', 'ptime', 'daynum', 'imgType', 'sourceFieldSuffix', 'hasCover', 'docid', 'tname', 'url_3w', 'dkeys', 'ipadcomment', 'tagList', 'category', 'interests', 'interest', 'recType', 'timestamp', 'sameSourceIndex', 'style']
其次是其他新闻的键:
['votecount', 'upTimes', 'downTimes', 'replyCount', 'commentStatus', 'postid', 'boardid', 'picCount', 'recommendSources', 'subscribedMotifs', 'sourceId', 'source', 'mtime', 'topicid', 'imgsrc', 'extraShowFields', 'priority', 'quality', 'ltitle', 'region', 'riskLevel', 'lmodify', 'title', 'digest', 'aheadBody', 'ptime', 'daynum', 'sourceFieldSuffix', 'docid', 'url_3w', 'dkeys', 'ipadcomment', 'category', 'interests', 'interest', 'recType', 'timestamp', 'sameSourceIndex', 'style']
因为我们要把这些信息存到数据库中,因此我们先找到它们中共同的键,在分析其含义:
['votecount', 'upTimes', 'downTimes', 'replyCount', 'commentStatus', 'postid', 'boardid', 'picCount', 'recommendSources', 'subscribedMotifs', 'sourceId', 'source', 'mtime', 'topicid','imgsrc', 'extraShowFields','priority', 'quality','region','riskLevel', 'lmodify', 'title','digest','ptime', 'daynum','sourceFieldSuffix', 'url_3w', 'dkeys', 'ipadcomment','category','interests', 'interest', 'recType', 'timestamp', 'sameSourceIndex', 'style']
共同包含的属性如上,头条中很多属性是其他新闻没有的,比如‘specialID’;其他新闻中也有未包含在共同属性中的属性,如'aheadBody',这些属性我们通过后面的分析觉得是否使用。
因为数据太多且对我们无用,因此我们只选择我们所需要的部分进行分析,比如新闻、图片的url,标题,支持度等等
审查元素获取新闻链接:
从上图中我们看出链接格式为https://3g.163.com/news/article/H5I0P90K0001899N.html?clickfrom=channel2018_news_newsList#offset=1
我们去掉文号后面的参数,发现仍然可以访问该新闻页。
因此我们只需要获得article后面的文章id即可。
从打印出的结果中可以看到,这个参数保存在posid中:
其他参数就根据需要获得了
分析结果如下:
'votecount',支持度
'replyCount',回复数
'postid',新闻链接(需组合)
'source',新闻来源
'mtime',发布时间
'imgsrc',图片链接
'priority',优先级
'title',标题
'digest',文摘
'category',分类
接下来就是讲获得的新闻数据保存到数据库中了。(后续取出id,将url设置为主键)
CREATE TABLE `epidemicplatform`.`news` (
`id` INT NOT NULL,
`url` VARCHAR(50) NULL,
`votecount` INT NULL,
`replyCount` INT NULL,
`source` VARCHAR(20) NULL,
`mtime` DATETIME NULL,
`imgsrc` VARCHAR(50) NULL,
`priority` INT NULL,
`title` VARCHAR(100) NULL,
`digest` VARCHAR(100) NULL,
`category` VARCHAR(10) NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `url_UNIQUE` (`url` ASC) VISIBLE);
接下来是将数据取出并插入数据库中,这里有一个问题,因为我们只能控制请求的条数,且不知道何时会有更新,因此请求到的数据可能存在重叠,也就是我们可能向数据库中插入已存在的数据。解决方案是:捕获插入已存在数据这个异常并忽略(因为数据已存在),其他异常则回滚:
# 'votecount',支持度
# 'replyCount',回复数
# 'postid',新闻链接(需组合)
# 'source',新闻来源
# 'mtime',发布时间
# 'imgsrc',图片链接
# 'priority',优先级
# 'title',标题
# 'digest',文摘
# 'category',分类
# url='https://3g.163.com/news/article/' + item['postid'] + '.html'
def get_news(news):
news_list = []
for item in news:
if 'postid' in item:
day = [item['postid'], item['votecount'],
item['replyCount'], item['source'], item['mtime'], item['imgsrc'], item['priority'],
item['title'], item['digest'], item['category']]
news_list.append(day)
return news_list
def insert_news(news_list):
db = pymysql.connect(host='localhost', user='root', password='#', db='epidemicplatform',
port=3306, charset='utf8')
cursor = db.cursor()
t = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
sql1 = 'insert into epidemicplatform.news(url,votecount,replyCount,source,mtime,imgsrc,priority,title,digest,' \
'category)' \
'values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
for item in news_list:
try:
cursor.execute(sql1, item)
db.commit()
print('插入成功:' + item[6])
except Exception as e:
# 检查异常原因是否是感兴趣的
result1 = re.search('Duplicate entry.*key.*PRIMARY', str(e))
# 如果是,什么都不用做
# 否则(不知道是什么原因),回滚
if result1 is None:
# 如果发生错误则回滚
db.rollback()
else:
print('数据库中已存在:' + item[0] + " pass!")
# 关闭数据库连接
print("插入完成!")
db.close()
cursor.close()
至此,获取新闻并存入数据库已经全部完成,接下来就是将这些抓取数据的动作全部自动化,也就是定时获取并更新数据,这些在将之后实现。
这里再分享一和可以获取当前风险地区的接口(两个参数,一个为该接口的key,可以去天行网上申请;另一个可选,为日期)
'http://api.tianapi.com/ncov/index'
数据获取如下:
highDangerCount = response['newslist'][0]['desc']['highDangerCount']
midDangerCount = response['newslist'][0]['desc']['midDangerCount']
midriskarea = response['newslist'][0]['riskarea']['mid']
highriskarea = response['newslist'][0]['riskarea']['high']