【python爬虫课程设计】类型数据爬取+数据可视化

发布时间 2023-12-28 17:26:00作者: yang-23

【python爬虫课程设计】类型数据爬取+数据可视化

选题的背景

稀土掘金作为国内最大的开发者社区,汇集了大量优质的技术文章和资源。通过爬取稀土掘金数据,可以深入了解当前技术领域的热点、趋势以及开发者的需求,为相关企业和机构提供有价值的参考信息。预期目标是分析热门技术主题、作者影响力、文章质量等方面,为企业决策、技术研发和人才培养提供数据支持。

主题式网络爬虫设计方案

  1. 主题式网络爬虫名称:稀土掘金主题爬虫
  2. 主题式网络爬虫爬取的内容与数据特征分析:
    • 爬取内容:课程掘金小册
    • 数据特征分析:所有小册、价钱、标签类型
  3. 实现思路:
    • 导入所需的库,包括json、requests和csv。
    • 设置请求头headers,包括User-Agent和Referer。
    • 定义CSV文件名result_csv和数据列表data_list。
    • 使用with语句打开CSV文件,并创建一个csv.writer对象。
    • 使用for循环每次执行以下操作:构造请求体data。使用requests库发送POST请求,获取响应结果。解析响应结果,提取所需数据。
  4. 技术难点:
    • 网站可能采用Ajax技术加载内容,需要分析请求过程,模拟登录和获取动态内容。
    • 网站可能会采取一定的反爬措施,如验证码、IP封禁等,需要设计相应的应对策略。

主题页面的结构特征分析

主题页面的结构与特征分析

  1. 顶部导航栏
  2. 类型导航位于中间的导航栏
  3. 下面是所有小册
  4. 不断往下滑,加载新的小册

Htmls 页面解析

  1. <div class="phone-show-menu isResourceVisible" data-V-925171a8> 顶部导航栏
  2. <div class="cates-label-wrap” data-v-0f9eb81c data-v-4b6aa530 data-v-7bb7d93a data-v-ffd280d8></div> 类型导航
  3. <span data-v-0c863bb9 data-v-f2a3effo title="CSS 工程化核心原理与实战”class="text-highlight” data-v-65b50b51>CSS 工程化核心原理与实战</span> 小册

节点(标签)查找方法与遍历方法

遍历方法for 循环:for i in range(0, 9): # 循环获取数据:9 次 =》 160 的量

网络爬虫程序设计

爬取数据

爬取 小册名、原价钱、类型、阅读人数 的网页数据并保存到 result.csv 文件中

import json
import requests
import csv


aid = 2608
uuid = 7308550062022411803
spider = 0

# 网站地址
url = "https://api.juejin.cn/booklet_api/v1/booklet/listbycategory?aid=" + str(aid) + "&uuid=" + str(uuid) + "&spider=" + str(spider)

# 请求头
headers = {
    # 设置浏览器查看的设备名称
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.200',

    # 从哪个网页跳转的
    'Referer':'https://juejin.cn/'
}

# csv文件
result_csv = 'res.csv'

# category 类型 | title 书名 |  pay_money 折扣后价钱 | buy_count 阅读/购买人数
data_list = ["category", "title", "pay_money", "buy_count"]

# 循环,先添加字段名
with open(result_csv, 'a+', encoding='gbk', newline='') as ff:
    writer = csv.writer(ff)
    writer.writerow(data_list)

# 循环获取数据:9 次 =》 160 的量
cursor = 0
category = ''
for i in range(0, 9):

    # 请求体
    data = {
        'category_id': "0",
        'cursor': str(cursor),
        'is_vip': 0,
        'limit': 20,
        'sort': 7
    }

    # 获取每页的数据量
    cursor += 20

    # requests 库发送一个 GET 请求到指定的 URL,并将响应结果存储在变量 req 中。
    req = requests.post(url, headers=headers, data=data)

    # 手动设置编码格式
    req.encoding = 'utf-8'
    a = req.text

    # 将 JSON 字符串转化为 Python 对象
    json_object = json.loads(a)

    # 通过键名获取对应的值
    b = json_object.get("data")

    # 类型id 对应的 类型名称
    cate_arr = [
        ["6809637769959178254", "6809637767543259144", "6809635626879549454",
         "6809635626661445640", "6809637773935378440", "6809637771511070734",
         "6809637776263217160", "6809637772874219534"],
        ["后端", "前端", "Android", "iOS", "人工智能", "开发工具", "代码人生", "阅读"]
    ]

    # 遍历解析后的数据
    for item in b:
        # 创建列表
        res_list = []

        # 打印 对比结果
        # print(item['base_info'])
        # print(item['max_discount'])

        # 提取解析数据中的 base_info 字典数据
        a = item['base_info']
        # 提取解析数据中的 max_discount 字典数据
        b = item['max_discount']

        # 打印 对比结果
        # print("类型:" + a['category_id'])
        # print("书名:" + a['title'])
        # print("阅读人数:" + str(a['buy_count']))
        # print("折扣后价钱:" + str(b['pay_money'] / 100))

        # category 类型 | title 书名 | pay_money 折扣后价钱 | buy_count 阅读/购买人数
        # category = a['category_id']
        title = a['title']
        pay_money = b['pay_money'] / 100
        buy_count = a['buy_count']

        # 将 ar['category_id'] 与 cate_arr 列表中的第一维列表进行判断
        for catei in cate_arr[0]:
            # 在匹配时,取出 cate_arr 列表中的第二维列表的值
            if catei == a['category_id']:
                # print(a['category_id'])
                # 打印,取出 cate_arr 列表中的第二维列表的值
                # print("类型:" + str(cate_arr[1][cate_arr[0].index(catei)]))

                category = str(cate_arr[1][cate_arr[0].index(catei)])

                # 追加数据,【输出 category 字段】
                res_list.append(category)
                break

        # 追加数据,【输出 title 字段】
        res_list.append(title)

        # 追加数据,【输出 pay_money 字段】
        res_list.append(pay_money)

        # 追加数据,【输出 buy_count 字段】
        res_list.append(buy_count)

        # 在一个已存在的 CSV 文件 result_csv 的末尾添加一行数据 res_list
        with open(result_csv, 'a+', encoding='gbk', newline='') as f:
            writer = csv.writer(f)
            writer.writerow(res_list)

散点图

根据 res.csv 文件中的 阅读人数和价格,画出散点图并且计算出回归线

import matplotlib.pyplot as plt
import pandas as pd
from sklearn.linear_model import LinearRegression

### 散点图、回归线:阅读人数、价格

def plot_reading_numbers(data):
    # 提取价钱数据
    pay_money = data['pay_money']

    # 提取阅读人数数据
    buy_count = data['buy_count']

    # 打印 价钱和阅读人数
    # print(pay_money)
    # print(buy_count)

    # 绘制散点图 (x, y)
    plt.scatter(pay_money, buy_count)

    # 设置 X横轴区间
    plt.xlim(0, 36)

    # 设置 Y横轴刻值
    plt.xticks([0, 5, 10, 15, 20, 25, 30, 36])

    # 设置 X横轴区间
    plt.ylim(0, 7000)

    # 设置 Y横轴刻值
    plt.yticks([0, 1000, 2000, 3000, 4000, 5000, 6000, 7000])

    # 计算回归线
    # 将 pay_money 的值转换为二维数组
    X = pay_money.values.reshape(-1, 1)

    # 将 buy_count 的值转换为二维数组
    y = buy_count.values.reshape(-1, 1)

    # 创建回归线
    reg = LinearRegression().fit(X, y)

    # 使用拟合得到的模型 reg 对 X 进行预测,并且设置线条颜色
    plt.plot(X, reg.predict(X), color='green')

    # 设置 X轴注解
    plt.xlabel('阅读人数')

    # 设置 Y轴注解
    plt.ylabel('价格')

    # 设置 标题
    plt.title('散点图 和 回归线')

    # 将图片保存为 sd.png
    plt.savefig('sd.png')

    # 实时显示图片
    plt.show()


if __name__ == "__main__":

    # 中文乱码
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 读取 CSV 文件
    data = pd.read_csv('res.csv', encoding='gbk')

    # 打印,对比结果
    # print(data)

    plot_reading_numbers(data)

饼图

根据 res.csv 文件中的 类型、购买人数 做出不同类型下的购买人数进行统计比例,使用饼图显示

import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np

### 饼图:类型、购买人数

def plot_reading_numbers(data):
    # 删除重复值(数据清洗)
    data = data.drop_duplicates()

    # print(data)

    # 将清洗后的数据添加到 category_list 列表中
    category_list = []
    for item in data['category'].value_counts().index:
        category_list.append(item)

    # print(category_list)

    # 设置比例图的每一块的颜色
    colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']

    # print(data['category'].value_counts().values)

    # 使用 matplotlib 库中的 plt.pie() 函数来绘制饼图
    plt.pie(data['category'].value_counts().values, labels=category_list, autopct='%1.1f%%', startangle=90)

    # 显示为圆(避免比例压缩为椭圆)
    plt.axis('equal')

    # 设置字体、并且支持中文
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 保存饼图
    plt.title('不同类型的购买人数的统计比例')

    # 将图片保存为 bin.jpg
    plt.savefig('bin.jpg')

    # 实时显示图片
    plt.show()


if __name__ == "__main__":
    # 中文乱码
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 读取 CSV 文件
    data = pd.read_csv('res.csv', encoding='gbk')

    # 打印,对比结果
    # print(data)

    plot_reading_numbers(data)

直方图

根据 res.csv 文件中的 类型、每本小册的价格 做一个平均价格,并且画出同类型下平均价钱的直方图

import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np

### 直方图:类型、平均价格

def plot_reading_numbers(data):
    # 对数据进行分组并计算平均价格
    grouped_data = data.groupby('category')['pay_money'].mean()

    # 绘制直方图
    plt.bar(grouped_data.index, grouped_data.values)

    # 设置 X 轴注解
    plt.xlabel('类型')

    # 设置 Y 轴注解
    plt.ylabel('平均价格')

    # 设置 标题
    plt.title('同类型下平均价钱')

    # 将图片保存为 zf.jpg
    plt.savefig('zf.jpg')

    # 实时显示图片
    plt.show()


if __name__ == "__main__":
    # 中文乱码
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 读取 CSV 文件
    data = pd.read_csv('res.csv', encoding='gbk')

    # 打印,对比结果
    # print(data)

    plot_reading_numbers(data)

词云图

根据 res.csv 文件中的 小册名 计算生成热门和推荐的词云图

import pandas as pd
from wordcloud import WordCloud
import matplotlib.pyplot as plt

### 词云图:类型

def plot_reading_numbers(data):

    # 提取title字段的数据
    titles = ' '.join(data['title'])

    # 设置字体文件的路径
    font_path = 'simhei.ttf'

    # 设置词云图的背景颜色
    background_color = 'white'

    # 设置词云图的宽度
    width = 800

    # 设置词云图的高度
    height = 800

    # 使用 generate() 方法生成词云图
    wordcloud = WordCloud(font_path=font_path,
                          background_color=background_color,
                          width=width,
                          height=height).generate(titles)

    # 使用imshow()方法显示词云图,并设置插值方式为双线性插值
    plt.imshow(wordcloud, interpolation='bilinear')

    # 关闭坐标轴
    plt.axis('off')

    # 将图片保存为 zf.jpg
    plt.savefig('cy.jpg')

    # 实时显示图片
    plt.show()


if __name__ == "__main__":
    # 中文乱码
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 读取 CSV 文件
    data = pd.read_csv('res.csv', encoding='gbk')

    # 打印,对比结果
    # print(data)

    plot_reading_numbers(data)

总结

  1. 我使用了阅读人数和价格这两个变量来绘制散点图,从散点图中可以看出,阅读人数和价格之间存在一定的关系。
  2. 我使用了类型和购买人数这两个变量来绘制饼图,通过观察饼图,直观地了解到各种类型的购买人数在总购买人数中的占比情况。
  3. 我使用了类型和平均价格这两个变量来绘制直方图,通过观察直方图,了解不同类型的平均价格分布情况,以及各类型在整体中的占比。
  4. 我使用了类型这个变量来生成词云图,通过观察词云图,直观地了解到不同类型的词汇在整体中的分布情况。

总代码量

import json
import requests
import csv


aid = 2608
uuid = 7308550062022411803
spider = 0

# 网站地址
url = "https://api.juejin.cn/booklet_api/v1/booklet/listbycategory?aid=" + str(aid) + "&uuid=" + str(uuid) + "&spider=" + str(spider)

# 请求头
headers = {
    # 设置浏览器查看的设备名称
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.200',

    # 从哪个网页跳转的
    'Referer':'https://juejin.cn/'
}

# csv文件
result_csv = 'res.csv'

# category 类型 | title 书名 |  pay_money 折扣后价钱 | buy_count 阅读/购买人数
data_list = ["category", "title", "pay_money", "buy_count"]

# 循环,先添加字段名
with open(result_csv, 'a+', encoding='gbk', newline='') as ff:
    writer = csv.writer(ff)
    writer.writerow(data_list)

# 循环获取数据:9 次 =》 160 的量
cursor = 0
category = ''
for i in range(0, 9):

    # 请求体
    data = {
        'category_id': "0",
        'cursor': str(cursor),
        'is_vip': 0,
        'limit': 20,
        'sort': 7
    }

    # 获取每页的数据量
    cursor += 20

    # requests 库发送一个 GET 请求到指定的 URL,并将响应结果存储在变量 req 中。
    req = requests.post(url, headers=headers, data=data)

    # 手动设置编码格式
    req.encoding = 'utf-8'
    a = req.text

    # 将 JSON 字符串转化为 Python 对象
    json_object = json.loads(a)

    # 通过键名获取对应的值
    b = json_object.get("data")

    # 类型id 对应的 类型名称
    cate_arr = [
        ["6809637769959178254", "6809637767543259144", "6809635626879549454",
         "6809635626661445640", "6809637773935378440", "6809637771511070734",
         "6809637776263217160", "6809637772874219534"],
        ["后端", "前端", "Android", "iOS", "人工智能", "开发工具", "代码人生", "阅读"]
    ]

    # 遍历解析后的数据
    for item in b:
        # 创建列表
        res_list = []

        # 打印 对比结果
        # print(item['base_info'])
        # print(item['max_discount'])

        # 提取解析数据中的 base_info 字典数据
        a = item['base_info']
        # 提取解析数据中的 max_discount 字典数据
        b = item['max_discount']

        # 打印 对比结果
        # print("类型:" + a['category_id'])
        # print("书名:" + a['title'])
        # print("阅读人数:" + str(a['buy_count']))
        # print("折扣后价钱:" + str(b['pay_money'] / 100))

        # category 类型 | title 书名 | pay_money 折扣后价钱 | buy_count 阅读/购买人数
        # category = a['category_id']
        title = a['title']
        pay_money = b['pay_money'] / 100
        buy_count = a['buy_count']

        # 将 ar['category_id'] 与 cate_arr 列表中的第一维列表进行判断
        for catei in cate_arr[0]:
            # 在匹配时,取出 cate_arr 列表中的第二维列表的值
            if catei == a['category_id']:
                # print(a['category_id'])
                # 打印,取出 cate_arr 列表中的第二维列表的值
                # print("类型:" + str(cate_arr[1][cate_arr[0].index(catei)]))

                category = str(cate_arr[1][cate_arr[0].index(catei)])

                # 追加数据,【输出 category 字段】
                res_list.append(category)
                break

        # 追加数据,【输出 title 字段】
        res_list.append(title)

        # 追加数据,【输出 pay_money 字段】
        res_list.append(pay_money)

        # 追加数据,【输出 buy_count 字段】
        res_list.append(buy_count)

        # 在一个已存在的 CSV 文件 result_csv 的末尾添加一行数据 res_list
        with open(result_csv, 'a+', encoding='gbk', newline='') as f:
            writer = csv.writer(f)
            writer.writerow(res_list)
            
            
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.linear_model import LinearRegression

### 散点图、回归线:阅读人数、价格

def plot_reading_numbers(data):
    # 提取价钱数据
    pay_money = data['pay_money']

    # 提取阅读人数数据
    buy_count = data['buy_count']

    # 打印 价钱和阅读人数
    # print(pay_money)
    # print(buy_count)

    # 绘制散点图 (x, y)
    plt.scatter(pay_money, buy_count)

    # 设置 X横轴区间
    plt.xlim(0, 36)

    # 设置 Y横轴刻值
    plt.xticks([0, 5, 10, 15, 20, 25, 30, 36])

    # 设置 X横轴区间
    plt.ylim(0, 7000)

    # 设置 Y横轴刻值
    plt.yticks([0, 1000, 2000, 3000, 4000, 5000, 6000, 7000])

    # 计算回归线
    # 将 pay_money 的值转换为二维数组
    X = pay_money.values.reshape(-1, 1)

    # 将 buy_count 的值转换为二维数组
    y = buy_count.values.reshape(-1, 1)

    # 创建回归线
    reg = LinearRegression().fit(X, y)

    # 使用拟合得到的模型 reg 对 X 进行预测,并且设置线条颜色
    plt.plot(X, reg.predict(X), color='green')

    # 设置 X轴注解
    plt.xlabel('阅读人数')

    # 设置 Y轴注解
    plt.ylabel('价格')

    # 设置 标题
    plt.title('散点图 和 回归线')

    # 将图片保存为 sd.png
    plt.savefig('sd.png')

    # 实时显示图片
    plt.show()


if __name__ == "__main__":

    # 中文乱码
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 读取 CSV 文件
    data = pd.read_csv('res.csv', encoding='gbk')

    # 打印,对比结果
    # print(data)

    plot_reading_numbers(data)
    

import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np

### 饼图:类型、购买人数

def plot_reading_numbers(data):
    # 删除重复值(数据清洗)
    data = data.drop_duplicates()

    # print(data)

    # 将清洗后的数据添加到 category_list 列表中
    category_list = []
    for item in data['category'].value_counts().index:
        category_list.append(item)

    # print(category_list)

    # 设置比例图的每一块的颜色
    colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']

    # print(data['category'].value_counts().values)

    # 使用 matplotlib 库中的 plt.pie() 函数来绘制饼图
    plt.pie(data['category'].value_counts().values, labels=category_list, autopct='%1.1f%%', startangle=90)

    # 显示为圆(避免比例压缩为椭圆)
    plt.axis('equal')

    # 设置字体、并且支持中文
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 保存饼图
    plt.title('不同类型的购买人数的统计比例')

    # 将图片保存为 bin.jpg
    plt.savefig('bin.jpg')

    # 实时显示图片
    plt.show()


if __name__ == "__main__":
    # 中文乱码
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 读取 CSV 文件
    data = pd.read_csv('res.csv', encoding='gbk')

    # 打印,对比结果
    # print(data)

    plot_reading_numbers(data)
    
    
import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np

### 直方图:类型、平均价格

def plot_reading_numbers(data):
    # 对数据进行分组并计算平均价格
    grouped_data = data.groupby('category')['pay_money'].mean()

    # 绘制直方图
    plt.bar(grouped_data.index, grouped_data.values)

    # 设置 X 轴注解
    plt.xlabel('类型')

    # 设置 Y 轴注解
    plt.ylabel('平均价格')

    # 设置 标题
    plt.title('同类型下平均价钱')

    # 将图片保存为 zf.jpg
    plt.savefig('zf.jpg')

    # 实时显示图片
    plt.show()


if __name__ == "__main__":
    # 中文乱码
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 读取 CSV 文件
    data = pd.read_csv('res.csv', encoding='gbk')

    # 打印,对比结果
    # print(data)

    plot_reading_numbers(data)
    
    
import pandas as pd
from wordcloud import WordCloud
import matplotlib.pyplot as plt

### 词云图:类型

def plot_reading_numbers(data):

    # 提取title字段的数据
    titles = ' '.join(data['title'])

    # 设置字体文件的路径
    font_path = 'simhei.ttf'

    # 设置词云图的背景颜色
    background_color = 'white'

    # 设置词云图的宽度
    width = 800

    # 设置词云图的高度
    height = 800

    # 使用 generate() 方法生成词云图
    wordcloud = WordCloud(font_path=font_path,
                          background_color=background_color,
                          width=width,
                          height=height).generate(titles)

    # 使用imshow()方法显示词云图,并设置插值方式为双线性插值
    plt.imshow(wordcloud, interpolation='bilinear')

    # 关闭坐标轴
    plt.axis('off')

    # 将图片保存为 zf.jpg
    plt.savefig('cy.jpg')

    # 实时显示图片
    plt.show()


if __name__ == "__main__":
    # 中文乱码
    plt.rcParams['font.sans-serif'] = ['SimHei']

    # 读取 CSV 文件
    data = pd.read_csv('res.csv', encoding='gbk')

    # 打印,对比结果
    # print(data)

    plot_reading_numbers(data)