欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 Python爬虫:爬取网络流行词制作词云

程序员文章站 2022-06-22 08:42:23
用网络热词来制作词云。...

荐
                                                        Python爬虫:爬取网络流行词制作词云

导入:

最近突然觉得,在生活中可以看到很多与词云类似的图片,(不知道是不是我的个性化广告,哈哈哈)总之,闲来无事,自己也写一个代码来生成词云。
用什么数据来生成呢?再三回忆,突然想起了之前有一个网络流行词的网站: 小鸡词典
荐
                                                        Python爬虫:爬取网络流行词制作词云
里面不仅有热词,还有对应的解释,以及点赞数,这次的主要目的不是爬虫而是词云,所以我会用点赞数来作为对应热词的值


分析及代码:

首先打开网站首页用开发者工具抓包并构造请求头:
荐
                                                        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条数据怎么够,于是我们要先研究一下其余的数据是怎么加载的。
荐
                                                        Python爬虫:爬取网络流行词制作词云
当我们向下滑动鼠标滚轮时发现,出现了以下的提示:到这里我们就不能再滑动了,但是当我们 登上账号 后就可以看到,我们可以永无止境的向下滑动,而且每次都是加载 20 条数据。
荐
                                                        Python爬虫:爬取网络流行词制作词云
最开始我还以为当我们向下滑动时,会再次请求一个链接,类似于翻页操作,这就很简单了啊。
虽然当我去检查抓包时,确实发现了如下图的数据,的确是重新请求了一个链接,不过这里又出现了问题:
荐
                                                        Python爬虫:爬取网络流行词制作词云
我们可以看到,浏览器先发送一个 OPTIONS 请求,得到回复:Message: {“title”:“OPTIONS”,“content”:“收到了OPTIONS请求”} 后再次向同一个网址发送了一个 POST 请求。这才得到了新加载的 20 条数据。
荐
                                                        Python爬虫:爬取网络流行词制作词云
荐
                                                        Python爬虫:爬取网络流行词制作词云
到这里,我们是否还需了解一下 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 模块只负责生成词云的数据
matplotlibpyplot 类才负责把词云画出来
安装时只需要输入命令: 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()  #显示

选用以下图片作为模型,可以画出一个和开篇一样的爱心词云。
荐
                                                        Python爬虫:爬取网络流行词制作词云

由于该网站的反爬机制,会封掉短时间内频繁访问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"}

荐
                                                        Python爬虫:爬取网络流行词制作词云


  1. OPTIONS 请求方法的主要用途有两个:
    1)获取服务器支持的HTTP请求方法;
    2)用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。 ↩︎

本文地址:https://blog.csdn.net/qq_44700693/article/details/107151432