20233210林渤程 2023-2024-2 实验4 Python综合实践

芝士就食知识 2024-05-25 17:02:12

课程:《Python程序设计》
班级: 2332
姓名: 林渤程
学号:20233210
实验教师:王志强
实验日期:2024年5月15日
必修/选修: 公选课

1.实验内容

利用python实现爬虫,爬取B站评论,并获得词云图

2. 实验过程及结果

1)引入函数库
其中csv用于保存,re、hashlib、time用于多页爬取,pandas等用于生成词云,具体用途在下面提到

import requests
import re
from bs4 import BeautifulSoup
import csv                   
import hashlib                    
import time
from urllib.parse import quote
import pandas as pd
from wordcloud import WordCloud
import matplotlib.pyplot as plt

2)请求获取数据
首先,用header假装自己是电脑,防止出现I am a teapot;其中data为字符串参数,具体数值可以在网页后端找到;最后,用request进行请求

img

def datasolve(next_page, date, w_rid, flag1, oid):
     headers = {
        'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
    }
    # I am a teapot
    url = 'https://api.bilibili.com/x/v2/reply/wbi/main'
    data = {
            'oid': oid,
            'type': '1',
            'mode': '2',
            'pagination_str': '{"offset":%s}' % next_page,
            'plat': '1',
            'web_location': '1315875',
            'w_rid': w_rid,
            'wts': date,
        }
   response = requests.get(url, params=data, headers=headers)

3)解析数据
首先,我们发现评论的位置被{}包裹起来,故使用json;而后我们逐一查找键值找到评论所在地,可以利用搜索快速查找,利用键值一层一层往下,最后使用循环将一页评论读完

img

img

img


def datasolve(next_page, date, w_rid, flag1, oid):
     headers = {
        'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
    }
    url = 'https://api.bilibili.com/x/v2/reply/wbi/main'
    data = {
            'oid': oid,
            'type': '1',
            'mode': '2',
            'pagination_str': '{"offset":%s}' % next_page,
            'plat': '1',
            'web_location': '1315875',
            'w_rid': w_rid,
            'wts': date,
        }
   response = requests.get(url, params=data, headers=headers)
   json_data = response.json()      #b站的评论响应内容被{}包裹起来,故用json
   all_reply = json_data['data']['replies']
   for reply in all_reply:
        message = reply['content']['message'].replace('\n', ',')    #去掉换行符
        like = reply['like']
        datalist = {
            'reply': message,
            'like': like,
        }
        savedata(datalist, flag1)
        flag1 = False
        print(datalist)

4)保存数据
用csv进行保存,写入表格,其中fieldnames为字段名,即表头,根据获取数据写出,用flag进行判断,防止写完一次、覆盖一次,应使用’a‘,进行追加;采用‘utf-8’来对爬去的信息进行解码

def savedata(datalist, flag):
    if flag:
        fe = open('data.csv', 'w', encoding = 'utf-8', newline='')
        csv_writer = csv.DictWriter(fe, fieldnames=[
            'reply',
            'like',
        ])      #字段名,即表头,根据获取数据
        csv_writer.writeheader()
        csv_writer.writerow(datalist)
    else:
        fe = open('data.csv', 'a', encoding='utf-8', newline='')
        csv_writer = csv.DictWriter(fe, fieldnames=[
            'reply',
            'like',
        ])
        csv_writer.writerow(datalist)

5)多页爬取

img

通过比较可以发现,不同的评论页的网址(滚动会出现不同的网址)只有pagination_str,w_rid,wts会变。其中wts为时间戳可直接通过time函数获取,通过学习我们可以发现下一页的pagination_str蕴含在本页中,故同提取评论一样可获得。
-通过不完全归纳法,可以大致看出不同视频只有oid变了

img

img

但通过在评论给的相应中搜索我们找不到w_rid在里面,通过学习可知其被加密,故进行泛搜索找到了其源代码

img

通过滚动页面,设置断点我们可以知道相关的参数,也通过学习与验算可知md5加密在函数库hashlib中

def Hash(date, next_page,flag,oid):
    #获取w_rid的值
    next_offset = '{"offset":%s}' % next_page
    en = [
        "mode=2",
        f"oid={oid}",
        f"pagination_str={quote(next_offset)}",
        "plat=1",
        "type=1",
        "web_location=1315875",
        f"wts={date}"
    ]
    ee = '&'.join(en)
    string = ee + "ea1db124af3c7062474693fa704f4ff8"                 #常数为H
    MD5 = hashlib.md5()
    MD5.update(string.encode('utf-8'))
    w_rid = MD5.hexdigest()
    return w_rid

6)云图绘制
df['reply'] 为自己设的字段名,font_path='C:/Windows/Fonts/simhei.ttf' 为字体路径(可通用)

def Cloud():           #生成词云,技术不行
    df = pd.read_csv('data.csv')
    text = " ".join(review for review in df['reply'])
    wordcloud = WordCloud(width=2000, height=2000, font_path='C:/Windows/Fonts/simhei.ttf',
                          background_color='white', min_font_size=10).generate(text)
    plt.figure(figsize=(20,20), facecolor=None)
    plt.imshow(wordcloud)
    plt.axis("off")
    plt.tight_layout(pad=0)
    plt.show()

img

7)源代码与运行视频

  • 经过微小的处理(微小处理请见错误分析)我们就可以得到源代码了
import requests
import re
from bs4 import BeautifulSoup
import csv
import hashlib
import time
from urllib.parse import quote
import pandas as pd
from wordcloud import WordCloud
import matplotlib.pyplot as plt

def datasolve(next_page, date, w_rid, flag1, oid):
    headers = {
        'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
    }
    # I am a teapot
    url = 'https://api.bilibili.com/x/v2/reply/wbi/main'
    if flag1:
        #常数在换网站需要修改
        data = {
            'oid': oid,
            'type': '1',
            'mode': '2',
            'pagination_str': '{"offset":%s}' % next_page,
            'plat': '1',
            'web_location': '1315875',
            'w_rid': w_rid,
            'wts': date,
        }
    else:
        #换网站需要修改
        data = {
            'oid': oid,
            'type': '1',
            'mode': '2',
            'pagination_str': next_page,
            'plat': '1',
            'web_location': '1315875',
            'w_rid': w_rid,
            'wts': date,
        }
    response = requests.get(url, params=data, headers=headers)
    #print(response.status_code)
    json_data = response.json()      #b站的评论响应内容被{}包裹起来,故用json
    #print(json_data)
    all_reply = json_data['data']['replies']

    #提取数据所在列表,字典取值一层一层往下
    for reply in all_reply:
        message = reply['content']['message'].replace('\n', ',')    #去掉换行符
        like = reply['like']
        datalist = {
            'reply': message,
            'like': like,
        }
        savedata(datalist, flag1)
        flag1 = False
        print(datalist)

    #下一页请求参数
    next_offset1 = json_data['data']['cursor']['pagination_reply']['next_offset']
    #可恶啊,真不知道为什么爬下一页的pagination_str会少掉‘\‘,(很多#print都是在排查错误),所以用正则提取数字重构一次
    #所以也多了好多条件语句,可能可以精简,但我累了

    next_offset_num = re.findall('cursor\":(\\d+)', next_offset1)[0]      #\d没有,要\\d,好像是被解释成Unicode字符
    next_offset = '{"offset":"{\\"type\\":3,\\"direction\\":1,\\"Data\\":{\\"cursor\\":%s}}"}' % next_offset_num
    #print(next_offset)
    return next_offset


    # html = response.text     # soup不能直接接收response
    # soup = BeautifulSoup(html, "html.parser")
    # all_rep = soup.find_all("span",class_="reply-content")
    # for rep in all_rep:
    #     print(rep.string)


def Hash(date, next_page, flag, oid):
    #获取w_rid的值
    if flag:
        next_offset = '{"offset":%s}' % next_page
        #print(next_offset)
        #print(quote(next_offset))
    else:
        next_offset = next_page
        #print(next_offset)
        #print(quote(next_offset))

    # 换网站需要修改
    en = [
        "mode=2",
        f"oid={oid}",
        f"pagination_str={quote(next_offset)}",
        "plat=1",
        "type=1",
        "web_location=1315875",
        f"wts={date}"
    ]
    ee = '&'.join(en)
    string = ee + "ea1db124af3c7062474693fa704f4ff8"
    MD5 = hashlib.md5()
    MD5.update(string.encode('utf-8'))
    w_rid = MD5.hexdigest()
    #print(w_rid)
    return w_rid


def savedata(datalist, flag):
    if flag:
        fe = open('data.csv', 'w', encoding = 'utf-8', newline='')
        csv_writer = csv.DictWriter(fe, fieldnames=[
            'reply',
            'like',
        ])      #字段名,即表头,根据获取数据
        csv_writer.writeheader()
        csv_writer.writerow(datalist)
    else:
        fe = open('data.csv', 'a', encoding='utf-8', newline='')
        csv_writer = csv.DictWriter(fe, fieldnames=[
            'reply',
            'like',
        ])
        csv_writer.writerow(datalist)


def Cloud():           #生成词云,技术不行
    df = pd.read_csv('data.csv')
    text = " ".join(review for review in df['reply'])
    wordcloud = WordCloud(width=2000, height=2000, font_path='C:/Windows/Fonts/simhei.ttf',
                          background_color='white', min_font_size=10).generate(text)
    plt.figure(figsize=(20,20), facecolor=None)
    plt.imshow(wordcloud)
    plt.axis("off")
    plt.tight_layout(pad=0)
    plt.show()

if __name__ == "__main__":  # 当程序执行时
    # 调用函数
    oid = input("请输入oid:")          #可能只有oid变了
    next_page = '""'
    flag1 = True
    for page in range(1, 11):     #可修改页数
        print("正在爬取第(",page,")页")
        date = int(time.time())
        w_rid = Hash(date, next_page,flag1, oid)
        #print(w_rid)
        next_page = datasolve(next_page, date, w_rid, flag1, oid)
        flag1 = False
    Cloud()

3. 实验过程中遇到的问题和解决过程

  • 问题1:天真的我想直接用soup去爬,结果毛都没有

img

问题1解决方案:通过观看教程,使用json进行爬取

  • 问题2:多页查找时算出的w_rid不对,一直权限不足

  • 问题2解决方案:很多#print都是在排查错误,不知道为什么爬下一页的pagination_str会少掉‘\‘,所以用正则提取数字重构一次

  • 问题3:正则表达式’\d‘出错

  • 问题3解决方案:要‘\d’,好像是被解释成Unicode字符

  • 问题4:重构后只有第一个可以,后面还不行

  • 问题4解决方案:使用flag进行判断,因为第一个无需重构,但在hash中要修改,还有在data中不是第一个的也要

  • 问题5:文件里写完一个覆盖一个

  • 问题5解决方案:用flag进行判断,w 还是a

实验体会

多了好多条件语句,可能可以精简,但我真的改不动了,这个加密是真的烦,一点不同就跳不到下一页,原本是想做舆情分析的,但找不到好的参考,所以转做词云了;做完这个实验感觉长脑子了,对爬虫更加理解,深深感受到爬虫速度之快,还有python的库好多、有好多函数。也学会了故障检测,怎么找错。

课程总结

1.老师很好,人帅心善;
2.对python的学习更加深入了,也理清了一些概念,如面向对象与面向过程的区别
3.老师的讲课内容非常生动形象,举得例子也很贴合,便于我们理解
4.建议:我觉得可以进行一个翻译,选取一个C语言的程序,让我们用这节课所学将它转成python实现同样的功能,加深印象

参考资料

...全文
191 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
内容概要:本文系统阐述了基于矩约束的最大熵方法在扩展不确定度评估中的理论与应用,提供了一套完整的Matlab代码实现方案。该方法依据最大熵原理,在仅知样本的均值、方差、偏度、峰度等低阶矩信息的前提下,通过求解拉格朗日乘子,推导出满足这些矩约束且信息熵最大的最优概率密度函数,从而实现对测量结果的非参数化、无偏估计。相较于传统依赖正态分布假设的评估方式,该方法更具普适性与鲁棒性,尤其适用于处理非对称、非高斯等复杂分布的实际测量数据。文中详细论述了理论模型的构建、数值求解算法的设计、概率密度函数的重建过程,并通过典型算例验证了其在提高评估准确性方面的优越性能。; 适合人群:具备概率统计、信息论基础知识及Matlab编程能力,从事精密测量、实验数据分析、质量控制、计量科学等相关领域的研究人员、工程师及研究生。; 使用场景及目标:①解决传统扩展不确定度评估中因错误分布假设导致的系统性偏差问题;②在缺乏先验分布知识的情况下,对复杂测量数据进行客观、稳健的不确定度评定;③为高精度科学实验、工业检测及计量认证提供理论严谨、工具完备的技术支撑。; 阅读建议:建议读者结合提供的Matlab代码深入理解算法实现,重点关注拉格朗日乘子的迭代求解、熵最大化过程及PDF重构等核心环节,并尝试代入实际数据进行验证与拓展,以充分掌握该方法的应用精髓。
内容概要:本文研究了基于鲸鱼优化算法(WOA)的多无人机三维协同路径规划方法,旨在实现最低成本目标,综合考虑路径长度、飞行高度、环境威胁和转弯角度等多种约束条件。通过构建多目标优化模型,并利用WOA算法进行求解,实现了多无人机在复杂三维空间中的集群避障与路径优化。文中详细阐述了问题建模过程、适应度函数设计、约束处理机制以及算法实现细节,并借助Matlab仿真验证了该方法在路径平滑性、避障能力和成本控制方面的有效性,为多无人机系统的自主协同作业提供了可靠的技术支撑与实践方案。; 适合人群:具备一定优化算法基础和Matlab编程能力,从事无人机控制、智能优化、路径规划等相关领域的科研人员及高校研究生。; 使用场景及目标:①解决复杂三维环境中多无人机协同避障与高效路径规划问题;②学习如何将鲸鱼优化算法应用于多目标工程优化任务;③掌握基于Matlab的智能算法仿真、性能评估与可视化分析方法; 阅读建议:建议读者结合提供的Matlab代码深入理解算法实现过程,重点关注目标函数的构建逻辑与多约束条件的处理策略,可通过调整环境参数、初始条件和算法参数开展对比实验,以全面掌握多无人机协同路径规划的核心机制与优化技巧。

110

社区成员

发帖
与我相关
我的任务
社区描述
人生苦短,我用Python!
python3.11 高校
社区管理员
  • blackwall0321
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧