荐 Python爬虫:爬取网络流行词制作词云
导入:
最近突然觉得,在生活中可以看到很多与词云类似的图片,(不知道是不是我的个性化广告,哈哈哈)总之,闲来无事,自己也写一个代码来生成词云。
用什么数据来生成呢?再三回忆,突然想起了之前有一个网络流行词的网站: 小鸡词典
里面不仅有热词,还有对应的解释,以及点赞数,这次的主要目的不是爬虫而是词云,所以我会用点赞数来作为对应热词的值。
分析及代码:
首先打开网站首页用开发者工具抓包并构造请求头:
header = {
'Host': 'jikipedia.com',
'Connection': 'keep-alive',
'Origin': 'https://jikipedia.com',
'Referer': 'https://jikipedia.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
}
经过查看源码可以看到,初次打开网页时会默认加载 20 条数据。也就是 20 个流行词,仅仅20条数据怎么够,于是我们要先研究一下其余的数据是怎么加载的。
当我们向下滑动鼠标滚轮时发现,出现了以下的提示:到这里我们就不能再滑动了,但是当我们 登上账号 后就可以看到,我们可以永无止境的向下滑动,而且每次都是加载 20 条数据。
最开始我还以为当我们向下滑动时,会再次请求一个链接,类似于翻页操作,这就很简单了啊。
虽然当我去检查抓包时,确实发现了如下图的数据,的确是重新请求了一个链接,不过这里又出现了问题:
我们可以看到,浏览器先发送一个 OPTIONS 请求,得到回复:Message: {“title”:“OPTIONS”,“content”:“收到了OPTIONS请求”} 后再次向同一个网址发送了一个 POST 请求。这才得到了新加载的 20 条数据。
到这里,我们是否还需了解一下 OPTIONS 1 请求?
其实啊,完全不用,这里有个特殊情况:细心的你应该会发现,该网站是基于大数据的,会自动给你推送流行词,所以每一次请求主页都会得到不同的 20 条数据 。
这下我们就只需要写出如何抓取主页的 20 条数据就行了。
注意项:
- 由于要进行模拟登录,所以还要添加请求头 ‘Cookies’ 字段。
- 由于要多次请求网页,所以将请求连接写成函数。
- 由于有些流行词才刚发布,点赞数为0,但是在网页中它是以 ‘ ’(空格)的形式存在的,所以一旦遇到这种情况要将 ‘ ’(空格)改为 0。
def request(url):
try:
proxies = {'http': random.choice(proxy)}
r = requests.get(url=url, headers=header, proxies=proxies)
r.raise_for_status()
r.encoding = 'utf-8'
return r
except:
print("请求失败!")
def fun(url):
likes = []
html = request(num2, url).text
words = parsel.Selector(html).xpath('//a[@class="card-content"]//strong/text()').extract()
like_html = parsel.Selector(html).xpath('//div[@class="like button hoverable"]').extract()
for li in like_html:
like = parsel.Selector(li).xpath('//div/text()').extract()[-1]
if like != ' ':
likes.append(like)
else:
likes.append(0)
for num in range(20):
data[words[num]] = int(likes[num])
画词云:
基本功能都已经实现,虽然还是有一点小调整,但是我要留在后面来说为什么。
数据现在已经有了,接下来就是画词云了:
首先导入画词云所需要的模块:
import numpy
import wordcloud
import matplotlib.pyplot as plt
wordcloud 模块只负责生成词云的数据
matplotlib 的 pyplot 类才负责把词云画出来
安装时只需要输入命令: pip install wordcloud ,它会自动将两个模块都安装好。(wordcloud 模块依赖于matplotlib 模块)
写出关键代码:(详注解)
def draw():
mask1 = numpy.array(PIL.Image.open('./Desktop/123.jpg')) #词云形状目录
wcloud = wordcloud.WordCloud(background_color='white', mask=mask1, font_path='C:/Windows/Fonts/STXINGKA.TTF') #创建了一个词云(不支持中文,指定字体,不然就是乱码())
wcloud.generate_from_frequencies(frequencies=data) #以频率(点赞数)为标准生成词云
plt.figure(dpi=1200)
plt.imshow(wcloud, interpolation='bilinear') # 显示内容 (bilinear 点阵方式:二维)
plt.axis('off') #关闭坐标显示
plt.show() #显示
选用以下图片作为模型,可以画出一个和开篇一样的爱心词云。
由于该网站的反爬机制,会封掉短时间内频繁访问的 IP (起码不是人的速度)和当前登录的账号,导致以后即使更换了 IP 登上账号以后还是不能访问该网站。
所以在请求代码的位置尽量多休眠几秒。
如果每次请求都要休眠几秒钟,那我请求 100 次呢?1000 次呢?… 总不可能为了用多一点的数据来画词云,就要在电脑前一直等着吧!
所以我使用了一个告警系统,可以通过微信来提示我的词云生成情况:成功或某一次请求失败!
def warning(num1, flag=1): # 0 失败 1 成功
par = {"num": str(num1)}
if flag == 1:
temp = '477464252017283072' //成功时的匹配码
else:
temp = '477464742239145984' //失败时的匹配码
Parameters = { //告警参数
'secretKey': '********************************',
'appCode': '477462730265071616',
'templateCode': temp,
'params': quote(str(par))
}
URL = 'https://api.*******.com/api/alarm'
r = requests.get(URL, params=Parameters)
print(r.text)
源码及结果:
import PIL
import time
import numpy
import tqdm
import random
import parsel
import requests
import wordcloud
import matplotlib.pyplot as plt
from urllib.parse import quote
header = {
'Host': 'jikipedia.com',
'Connection': 'keep-alive',
'Origin': 'https://jikipedia.com',
'Referer': 'https://jikipedia.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
'Cookie': '填写自己的 Cookies '
}
proxy = ['HTTP://106.42.216.132:9999', 'HTTP://115.221.242.206:9999', 'HTTP://163.204.245.77:9999',
'HTTP://125.110.93.8:9000', 'HTTP://175.43.59.50:9999', 'HTTP://120.83.99.101:9999',
'HTTP://171.11.178.229:9999', 'HTTP://123.169.168.66:9999', 'HTTP://122.4.43.151:9999',
'HTTP://122.243.8.64:9000', 'HTTP://1.197.204.239:9999', 'HTTP://163.204.247.121:9999',
'HTTP://59.62.25.154:9000', 'HTTP://39.96.220.231:8888', 'HTTP://163.204.242.255:9999',
'HTTP://113.195.17.111:9999', 'HTTP://163.204.246.180:9999', 'HTTP://110.243.31.197:9999',
'HTTP://114.224.223.164:9999', 'HTTP://125.108.78.245:9000', 'HTTP://120.83.98.217:9999',
'HTTP://112.84.98.40:9999', 'HTTP://122.4.42.59:9999']
data = {}
num1 = 100
def request(num2, url):
try:
proxies = {'http': random.choice(proxy)}
r = requests.get(url=url, headers=header, proxies=proxies)
r.raise_for_status()
r.encoding = 'utf-8'
return r
except:
warning(num2, 0)
def fun(num2, url):
likes = []
try:
time.sleep(3)
html = request(num2, url).text
words = parsel.Selector(html).xpath('//a[@class="card-content"]//strong/text()').extract()
like_html = parsel.Selector(html).xpath('//div[@class="like button hoverable"]').extract()
for li in like_html:
like = parsel.Selector(li).xpath('//div/text()').extract()[-1]
if like != ' ':
likes.append(like)
else:
likes.append(0)
for num in range(20):
data[words[num]] = int(likes[num])
except:
warning(num2, 0)
def draw():
mask1 = numpy.array(PIL.Image.open('./Desktop/123.jpg'))
wcloud = wordcloud.WordCloud(background_color='white', mask=mask1, font_path='C:/Windows/Fonts/STXINGKA.TTF')
wcloud.generate_from_frequencies(frequencies=data)
plt.figure(dpi=1200)
plt.imshow(wcloud, interpolation='bilinear')
plt.axis('off')
plt.show()
def warning(num1, flag=1): # 0 失败 1 成功
par = {"num": str(num1)}
if flag == 1:
temp = '477464252017283072'
else:
temp = '477464742239145984'
Parameters = {
'secretKey': '**************************',
'appCode': '477462730265071616',
'templateCode': temp,
'params': quote(str(par))
}
URL = 'https://api.******.com/api/alarm'
r = requests.get(URL, params=Parameters)
print(r.text)
if __name__ == '__main__':
url = 'https://jikipedia.com/'
for num in tqdm.tqdm(range(num1),desc="正在统计:"):
fun(num, url)
warning(num1)
draw()
结果:
正在统计:: 100%|██████████| 100/100 [07:37<00:00, 4.02s/it]
{"code":"200","data":null,"message":"SUCCESS"}
-
OPTIONS 请求方法的主要用途有两个:
1)获取服务器支持的HTTP请求方法;
2)用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。 ↩︎
本文地址:https://blog.csdn.net/qq_44700693/article/details/107151432