八卦是人的天性,我作为众多吃瓜群众中的一员,当然也不会放过娱乐圈中的每一个热点。
接下来我会抓取企鹅网的娱乐版块 https://new.qq.com/ch/ent/
看看各位娱乐小编是如何报道娱乐热点的。
具体目标如下图:(红色方框内的标题)
- 第一步就是“观察与分析”,不断下拉滚动条,右键点击查看源代码,右键点击检查,这些都是基本操作了,可以发现网站是Ajax加载,返回的数据都在Json里,如下图:
- 接下来就可以进行基本的抓取,代码如下(文件名为news_of_ent_v1.py):
import requests
import json
import uagent #我自己编写的一个获取随机user-agent的脚本,可参考https://blog.youkuaiyun.com/eighttoes/article/details/82996377
url = ('https://pacaio.match.qq.com/irs/rcd?cid=146&token=49cbb2154853ef1a74ff4e5372337'
'2ce&ext=ent&page=3&expIds=20181129V094JT|20181129A09LA4|20181129A09DI3|h08046y2'
'39w|20181129A0AEFT|20181129A09L7P|20181129A0A0A3|w0804cm6v49|20181129A07WGU|201'
'81129V07R1F|20181129A07YTG|i0804um2sgw|20181129A03RFA|20181129V08K9U|20181129A0'
'752A|r0804pauuow|20181129A03M8L|20181129V05VUW|20181129A07RY8|i0804rrvezl&callb'
'ack=__jp9')
def get_page(url):
headers = {'User-Agent': uagent.get_ua()}
response = requests.get(url = url, headers = headers)
index = response.text.index('{')
text = response.text[index:-1] #因为返回的字符串不符合Json格式,所有需要截取
return text
def parse(text):
dic = json.loads(text)
for i in dic['data']:
title = i['title']
print(title)
if __name__ == '__main__':
text = get_page(url)
parse(text)
- 第三步可以开始考虑如何进行多页的数据抓取,一般来说可以观察多个url之间的规律,
url参数有变化的分别是page,expIds,callback。
page和callback都很好理解,就是一个递增的数字,至于expIds,这么一大串的东西是什么呢,我从刚刚抓取的Json数据里找到了线索,其中id字段就组成下一页url的关键信息。
那么接下来就可以开始编辑代码了,如下所示(文件名为news_of_ent_v2.py):
import requests
import json
import uagent #我自己编写的一个获取随机user-agent的脚本,可参考https://blog.youkuaiyun.com/eighttoes/article/details/82996377
def get_page(n, expIds): #page从1开始,callback = page + 6
base_url = 'https://pacaio.match.qq.com/irs/rcd'
payload = {
'cid': '146',
'token': '49cbb2154853ef1a74ff4e53723372ce',
'ext': 'ent',
'page': str(n),
'expIds': expIds,
'callback': '__jp' + str(n + 6)
}
headers = {'User-Agent': uagent.get_ua()}
response = requests.get(url = base_url, params = payload, headers = headers)
index = response.text.index('{')
text = response.text[index:-1] #因为返回的字符串不符合Json格式,所有需要截取
return text
def parse_title(text):
dic = json.loads(text)
for i in dic['data']:
title = i['title']
print(title)
def parse_id(text):
dic = json.loads(text)
expIds = ''
for i in dic['data']:
expIds += i['id']
expIds += '|'
return expIds[:-1]
if __name__ == '__main__':
expIds = ('20181129001615|20181129A0JFDT|20181128A0Z1JV|l0804gy5rsa|20181129A0K'
'LSB|20181129A0D0LP|20181129A02B6B|n0804d5mx3y|20181128A1K7IZ|20181129'
'A09LA4|20181129A060VB|s0804loccct|20181129A0KIZU|20181129A0AEFT|20181'
'129A0PGAG|w0804wyseww|20181129009640|20181129A0JLZQ|20181129A06G5R')
for n in range(1, 11):
text = get_page(n, expIds)
parse_title(text)
expIds = parse_id(text)
修改了get_page()函数,添加了构造url的逻辑,而不是直接把url当作参数传入,然后添加了一个解析expIds的函数。
- 第四步就要开始考虑保存数据了,因为数据量不大,而且只有1个字段,直接保存为一个csv文件就可以了。
代码如下(文件名为news_of_ent_v3.py):
import requests
import json
import uagent #我自己编写的一个获取随机user-agent的脚本,可参考https://blog.youkuaiyun.com/eighttoes/article/details/82996377
import csv
def get_page(n, expIds): #page从1开始,callback = page + 6
base_url = 'https://pacaio.match.qq.com/irs/rcd'
payload = {
'cid': '146',
'token': '49cbb2154853ef1a74ff4e53723372ce',
'ext': 'ent',
'page': str(n),
'expIds': expIds,
'callback': '__jp' + str(n + 6)
}
headers = {'User-Agent': uagent.get_ua()}
response = requests.get(url = base_url, params = payload, headers = headers)
index = response.text.index('{')
text = response.text[index:-1] #因为返回的字符串不符合Json格式,所有需要截取
return text
def parse_title(text):
dic = json.loads(text)
titles = [i['title'] for i in dic['data']]
return titles
def parse_id(text):
dic = json.loads(text)
expIds = ''
for i in dic['data']:
expIds += i['id']
expIds += '|'
return expIds[:-1]
def save(data):
#encoding用一个比较大的汉字字符集,防止出现不能识别的汉字
with open('titles.csv', 'a', newline = '', encoding = 'GB18030') as c:
writer = csv.writer(c)
for i in data:
writer.writerow([i])
if __name__ == '__main__':
#这里对第一个expIds进行硬编码
expIds = ('20181129001615|20181129A0JFDT|20181128A0Z1JV|l0804gy5rsa|20181129A0K'
'LSB|20181129A0D0LP|20181129A02B6B|n0804d5mx3y|20181128A1K7IZ|20181129'
'A09LA4|20181129A060VB|s0804loccct|20181129A0KIZU|20181129A0AEFT|20181'
'129A0PGAG|w0804wyseww|20181129009640|20181129A0JLZQ|20181129A06G5R')
for n in range(1, 11):
text = get_page(n, expIds)
data = parse_title(text)
save(data)
print('the', n, 'page ok')
expIds = parse_id(text)
将parse_title()函数改为返回一个列表推导式,并新增了一个save()函数。
####我一开始打算抓取1万页的数据,不过到了约20页左右,每页的标题数量就从20个下降到4-5个,我一开始以为是遇到什么反爬策略了,于是用浏览器加载看看,发现也是一样。
然后用脚本抓取到大概2000多页的时候,直接就没有标题返回了,我想应该是企鹅网直接把旧的过期缓存删掉吧,正常人也不会看一个版的新闻,下拉到2000多页。。。
这里我挖掘了3235个标题,下面进行一下简要的分析。
首先我发现,作为一名专业的小编,在起标题的时候,是绝对不能使用句号的,但是可以使用问号?和感叹号!
而且不能使用简单的几个词语来起标题,标题一般都比较长,需要用逗号来拼接。
至于标题的字数一般控制在20-32个左右,只有极少数会出现在10个字以下,或者35个字以上。
由于标题必须和内容具有相关性,相信只要具有初中语文水平的同学都会知道这个道理。
虽然近年来,出现了非常非常多的标题党,但是对于标题中的主角一般不会假,因此接下来可以通过标题来看看这两天(我这篇博客写于18年11月29日)热度最高的10位艺人分别是谁?
可以看出基本和昨天(18年11月28日)的娱乐新闻八九不离十,除了赵丽颖,我不知道发生了什么。。。
总结
通过分析Ajax,仅仅利用requests和json库就可以进行数据的挖掘,保存数据利用了csv库。
至于后期的数据可视化,分别使用了pandas读取并操作csv,jieba进行分词,collections中的Counter进行词频统计,plt画图。