文本分析¶

In [1]:
#爬取人民网新闻
import requests
from bs4 import BeautifulSoup
import openpyxl
In [2]:
# 创建Excel表格
wb = openpyxl.Workbook()
sheet = wb.active
sheet.append(["title", "link", "date", "content"])
In [3]:
# 爬取网页标题和链接的函数
def get_news_links(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')
    links = []
    
    # 从 ul.list_16 中提取每个 li 的新闻标题和链接
    for li in soup.select('ul.list_16 li'):
        a_tag = li.find('a')  # 获取新闻链接和标题
        title = a_tag.get_text().strip()
        link = a_tag.get('href')  # 提取相对链接
        if not link.startswith('http'):
            link = "http://finance.people.com.cn" + link  # 补全相对链接
        
        # 获取新闻日期
        date_tag = li.find('em')
        date = date_tag.get_text().strip() if date_tag else "未知日期"
        
        links.append((title, link, date))
    return links
In [4]:
# 爬取每篇新闻的正文内容
def get_news_content(link):
    response = requests.get(link)
    soup = BeautifulSoup(response.content, 'html.parser')
    
    # 查找正文,定位到 div.rm_txt_con 并提取所有 p 标签内容
    article = soup.find('div', class_='rm_txt_con')  # 根据HTML结构提取内容
    if article:
        paragraphs = article.find_all('p')
        content = "\n".join([p.get_text().strip() for p in paragraphs if p.get_text().strip()])
    else:
        content = "无正文内容"
    
    return content
In [5]:
# 爬取多个新闻标题和链接
url = "http://finance.people.com.cn/GB/70846/index1.html"
news_links = get_news_links(url)
In [6]:
# 将数据写入Excel
for title, link, date in news_links:
    print(f"正在处理: {title}")
    # 获取每篇新闻的正文内容
    content = get_news_content(link)
    # 将标题、链接、发布时间和正文写入Excel
    sheet.append([title, link, date, content])
正在处理: 油价调整!5月19日24时起汽、柴油价格每吨分别降低230元和220元
正在处理: 业界:把握人工智能发展趋势 以用促建赋能高质量发展
正在处理: 深化区域交流合作 第26届青洽会将在青海西宁举办
正在处理: 张于喆 郑腾飞:加快构建多层次数据流通交易体系
正在处理: 市场监管总局公布首批商品过度包装检验检测机构名单
正在处理: “数据要素产业服务平台(深圳试点)暨数据要素×应用场景生态实验室”合作签约仪式举行
正在处理: “三驾马车”协同发力 国民经济发展质量稳步提升
正在处理: 黄琦:数字技术是全面绿色转型的“催化剂”
正在处理: 国家统计局:部分工业行业价格有所改善
正在处理: 九部门部署科技服务业高质量发展 明确十大重点领域
正在处理: 国家统计局:我国经济有条件、有能力、有底气应对各种风险挑战
正在处理: 国资央企提升品牌建设效能 凸显功能价值
正在处理: 结构性减税降费政策现成效 我国创新动能增势良好
正在处理: 国家统计局:多项指标稳定增长 展现经济强大韧性
正在处理: 1至4月国家铁路发送货物12.99亿吨 日均装车18万车
正在处理: 4月份我国国民经济顶住压力稳定增长
正在处理: 逾六成专精特新中小企业营收较上年实现增长或持平
正在处理: 水利部:中国愿同各方携手合作推动生态大坝技术研发与应用
正在处理: 人工智能为知识产权保护注入新动能
正在处理: 走近钱学森、郭永怀……一场与“力学”的亲密接触
正在处理: 研究所变身“游园会”:遇见哪吒,探秘理化
正在处理: 12306团队:“每行代码都是承诺”
正在处理: 公众科学日沉浸式漫游“物理世界”
正在处理: 分子工具能精准“开关”大脑回路
正在处理: 去年我国卫星导航产业产值达5758亿元
正在处理: “鲲龙”批生产首架机完成生产试飞
正在处理: “三体计算星座”为啥把计算送上天
正在处理: 中小银行改革化险提速 多家村镇银行被吸收合并
正在处理: “硬本领”“软实力”已成中国品牌全球化的底色
正在处理: 双边本币互换的积极作用正不断显现
正在处理: 年内REITs发行规模超113亿元 险资战投身份是亮点
正在处理: 共探开放包容金融体系 解码全球经济新未来
正在处理: 以高质量并购驱动产业升级 更好发挥资本市场枢纽功能
正在处理: 完善城市更新顶层设计 打造宜居、韧性、智慧城市
正在处理: 八大行动全力释放数据要素价值 新质生产力得以不断壮大
正在处理: 天问二号探测器已转入发射区 计划5月底择机发射
正在处理: 江苏启东:多举措助力民营企业高质量发展
正在处理: 微塑料“入侵”:真相、争议与行动
正在处理: 甘肃张掖“太空信使”划破苍穹
正在处理: 共建“一带一路”国家青年聚浙江绍兴 共话科技人文交流
正在处理: 工程机械迎电动化新潮流 中国企业抢先机
正在处理: 第34届哈洽会启幕 1500余家企业参展
正在处理: 2025世界雷达博览会开幕 李德仁院士冀推进和实现时空智能
正在处理: 先行指标透射经济发展动能强劲 中国高质量发展“枝繁叶茂”
正在处理: 中国东部小县城撬动全球轮胎市场
In [7]:
# 保存Excel文件
wb.save("news_data.xlsx")
print("爬取完成并保存到 news_data.xlsx")
爬取完成并保存到 news_data.xlsx
In [8]:
# %pip install jieba
In [9]:
#清洗文本
import pandas as pd
import os 
import numpy as np
import re
import jieba
new_data = pd.DataFrame()
# 定义文件路径
input_file_path = r"news_data.xlsx"
news_data = pd.read_excel(input_file_path)
In [10]:
#文本预处理
def clean_content(text):
    if pd.isna(text):
        return text
    
    text = str(text)

    # 1. 清除日期格式
    date_patterns = [
        r"\d{4}[-年/.]\d{1,2}[-月/.]\d{1,2}[日]?",     # 2023年12月31日, 2023-12-31, 2023/12/31
        r"\d{1,2}[-/.]\d{1,2}(?!\d)",                # 12/31, 12-31
        r"\d{4}年",                                  # 2023年
        r"\d{1,2}月\d{1,2}日",                       # 12月31日
        r"\d{1,2}月",                                # 12月
        r"\d{1,2}日",                                # 31日
        r"\d{4}"                                     # 单独年份
    ]
    for pattern in date_patterns:
        text = re.sub(pattern, '', text)

    # 2. 删除“(记者XXX)”类文本
    text = re.sub(r'(记者[^)]*)', '', text)

    # 3. 删除“人民网××电”类地点标签
    text = re.sub(r'人民网.{1,4}电\s*', '', text)

     # 4. 删除百分比数字(如 57%)
    text = re.sub(r'\d+%+', '', text)

    return text

news_data['content'] = news_data['content'].apply(clean_content)
In [11]:
# 加载停用词列表
stop_words_path = r"cn_stopwords.txt"
with open(stop_words_path, 'r', encoding='gbk') as f:
    stop_words = [line.strip() for line in f.readlines()]
In [12]:
# 定义去除停用词的函数
def remove_stopwords(text):
    words = jieba.cut(text)  # 使用 jieba 进行分词
    return ' '.join([word for word in words if word not in stop_words])
In [13]:
# 对 content 列进行分词并去除停用词,将处理后的文本存入新列 'cleaned_content'
news_data['cleaned_content'] = news_data['content'].apply(remove_stopwords)
news_data['cleaned_title'] = news_data['title'].apply(remove_stopwords)
news_data.to_excel( r".\cleaned_news_data.xlsx",index = False)
print(news_data.head())
Building prefix dict from the default dictionary ...
Loading model from cache /tmp/jieba.cache
Loading model cost 0.403 seconds.
Prefix dict has been built successfully.
                                 title  \
0  油价调整!5月19日24时起汽、柴油价格每吨分别降低230元和220元   
1            业界:把握人工智能发展趋势 以用促建赋能高质量发展   
2             深化区域交流合作 第26届青洽会将在青海西宁举办   
3              张于喆 郑腾飞:加快构建多层次数据流通交易体系   
4             市场监管总局公布首批商品过度包装检验检测机构名单   

                                                link        date  \
0  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   
1  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   
2  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   
3  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   
4  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   

                                             content  \
0  制图:罗知之\n据国家发展改革委网站消息,根据近期国际市场油价变化情况,按照现行成品油价格形...   
1  当前,人工智能作为引领新一轮科技革命和产业变革的技术,改变着人类的生产生活方式。如何抢抓人工...   
2  “第26届中国·青海绿色发展投资贸易洽谈会(以下简称青洽会)将于至在西宁举办。”青海省人民政...   
3  推动数字技术与实体经济深度融合,是建设现代化产业体系的必然要求,是践行高质量发展的重要途径。...   
4  据国家市场监管总局网站消息,近日,市场监管总局印发通知,公布首批获得总局资质认定的具有商品过...   

                                     cleaned_content  \
0  制图 罗知 \n 国家 发展 改革 委 网站 消息 近期 国际 市场 油价 变化 情况 现行...   
1  当前 人工智能 引领 新一轮 科技 革命 产业 变革 技术 改变 人类 生产 生活 方式 抢...   
2  26 届 中国 · 青海 绿色 发展 投资 贸易 洽谈会 以下 简称 青洽会 西宁 举办 青...   
3  推动 数字 技术 实体 经济 深度 融合 建设 现代化 产业 体系 必然 要求 践行 高质量...   
4  国家 市场监管 总局 网站 消息 近日 市场监管 总局 印发 通知 公布 首批 获得 总局 ...   

                                 cleaned_title  
0  油价 调整 月 19 日 24 时起汽 柴油 价格 每吨 降低 230 元 220 元  
1            业界 把握 人工智能 发展趋势   以用 促建 赋能 高质量 发展  
2              深化 区域 交流 合作   26 届 青洽会 青海 西宁 举办  
3            张于 喆   郑 腾飞 加快 构建 多层次 数据 流通 交易 体系  
4           市场监管 总局 公布 首批 商品 过度 包装 检验 检测 机构 名单  
In [14]:
#生成词云图全流程
#对文本词组计数
content = news_data.content.values.tolist()
content_S = []
for line in content:
    current_segment = jieba.lcut(line)
    if len(current_segment) > 1 and current_segment !='\r\n':
        content_S.append(current_segment)
# print(content_S)
In [15]:
#转化成列表格式
df_content = pd.DataFrame({'content_S': [' '.join(row) for row in content_S]})
df_stop_words = pd.DataFrame({'stopwords':[' '.join(row) for row in stop_words]})
In [16]:
# 停用词清理函数
def drop_stopwords(contents, stopwords):
    contents_clean = []
    all_words = []
    for line in contents:
        line_clean = []
        for word in line:
            if word in stopwords:
                continue
            line_clean.append(word)
            all_words.append(str(word))
        contents_clean.append(line_clean)
    return contents_clean, all_words

contents_clean, all_words = drop_stopwords(content_S, stop_words)
In [17]:
# 正确词频统计
df_all_words = pd.DataFrame({'all_words': all_words})
words_count = df_all_words.groupby(by='all_words').size().reset_index(name='count')
words_count = words_count.sort_values(by='count', ascending=False).reset_index(drop=True)
words_count = words_count.drop(index=words_count.index[:2])  # 可视需要调整删除前两位
In [18]:
# %pip install wordcloud
In [19]:
#词云图生成
from wordcloud import WordCloud
import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib
matplotlib.rcParams['figure.figsize'] = (10.0, 5.0)
wordcloud = WordCloud(font_path = r"/usr/share/fonts/truetype/SimHei/SimHei.ttf",background_color = "white",max_font_size=80)
word_frequence = {x[0]:x[1] for x in words_count.head(100).values}
wordcloud = wordcloud.fit_words(word_frequence)
plt.imshow(wordcloud, interpolation="bilinear")
plt.axis("off")
plt.show()
In [20]:
#提取新闻文本关键词——TF-IDF
import pandas as pd

# 重新加载并处理数据
file_path = r"cleaned_news_data.xlsx"
news = pd.read_excel(file_path)

# 提取 content 列中的文本内容
documents = news['cleaned_content'].tolist()

# 初始化 TfidfVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf_vectorizer = TfidfVectorizer(max_df=0.85, min_df=2, use_idf=True, ngram_range=(1,2))

# 计算TF-IDF矩阵
tfidf_matrix = tfidf_vectorizer.fit_transform(documents)

# 获取词汇表
feature_names = tfidf_vectorizer.get_feature_names_out()
In [21]:
# 提取每篇文档的关键词
def get_top_keywords(tfidf_matrix, feature_names, top_n=5):
    top_keywords = []
    for i in range(tfidf_matrix.shape[0]):
        row = tfidf_matrix[i].toarray()[0]
        sorted_indices = row.argsort()[::-1][:top_n]
        keywords = [feature_names[index] for index in sorted_indices]
        top_keywords.append(keywords)
    return top_keywords
In [22]:
# 获取每篇文章的前5个关键词
news['main_words'] = get_top_keywords(tfidf_matrix, feature_names, top_n=5)
In [23]:
# 保存新的表格
new_file_path =r".\news_data_keywords_expanded.xlsx"
news.to_excel(new_file_path, index=False)
In [24]:
print(news.head())
                                       title  \
0                  业界:把握人工智能发展趋势 以用促建赋能高质量发展   
1                   深化区域交流合作 第26届青洽会将在青海西宁举办   
2                    张于喆 郑腾飞:加快构建多层次数据流通交易体系   
3                   市场监管总局公布首批商品过度包装检验检测机构名单   
4  “数据要素产业服务平台(深圳试点)暨数据要素×应用场景生态实验室”合作签约仪式举行   

                                                link        date  \
0  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   
1  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   
2  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   
3  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   
4  http://finance.people.com.cn/n1/2025/0519/c100...  2025-05-19   

                                             content  \
0  当前,人工智能作为引领新一轮科技革命和产业变革的技术,改变着人类的生产生活方式。如何抢抓人工...   
1  “第26届中国·青海绿色发展投资贸易洽谈会(以下简称青洽会)将于至在西宁举办。”青海省人民政...   
2  推动数字技术与实体经济深度融合,是建设现代化产业体系的必然要求,是践行高质量发展的重要途径。...   
3  据国家市场监管总局网站消息,近日,市场监管总局印发通知,公布首批获得总局资质认定的具有商品过...   
4  近日,人民网旗下人民数据公司与深圳市社会组织总会、深圳市企业联合会、会邦数据科技(深圳)有限...   

                                     cleaned_content  \
0  当前 人工智能 引领 新一轮 科技 革命 产业 变革 技术 改变 人类 生产 生活 方式 抢...   
1  26 届 中国 · 青海 绿色 发展 投资 贸易 洽谈会 以下 简称 青洽会 西宁 举办 青...   
2  推动 数字 技术 实体 经济 深度 融合 建设 现代化 产业 体系 必然 要求 践行 高质量...   
3  国家 市场监管 总局 网站 消息 近日 市场监管 总局 印发 通知 公布 首批 获得 总局 ...   
4  近日 人民网 旗下 人民 数据 公司 深圳市 社会 组织 总会 深圳市 企业 联合会 会邦 ...   

                                       cleaned_title               main_words  
0                  业界 把握 人工智能 发展趋势   以用 促建 赋能 高质量 发展   [人工智能, 发展, 产业, 革命, 模型]  
1                    深化 区域 交流 合作   26 届 青洽会 青海 西宁 举办     [主宾, 签约, 展区, 本届, 对接]  
2                  张于 喆   郑 腾飞 加快 构建 多层次 数据 流通 交易 体系     [数据, 交易, 价值, 实体, 突出]  
3                 市场监管 总局 公布 首批 商品 过度 包装 检验 检测 机构 名单  [过度, 商品, 检验, 检测, 检验 检测]  
4  数据 要素 产业 服务平台 深圳 试点 暨 数据 要素 × 应用 场景 生态 实验室 合作 ...  [数据, 数据 要素, 深圳, 要素, 人民]  

LDA Example 1¶

In [25]:
## LDA模型

from sklearn.decomposition import LatentDirichletAllocation  
from sklearn.feature_extraction.text import CountVectorizer  
import matplotlib.pyplot as plt  
from matplotlib import font_manager  

# 1. Sample documents in English  
docs = [  
    "The economy is showing improvement and growth.",  
    "Stocks and bonds are popular investment options.",  
    "Economic cycles can affect the business outlook.",  
    "Company profits are a sign of good business health.",  
    "News outlets often report on market trends and cycles.",  
]  

# 2. Convert the documents into a document-term matrix  
vectorizer = CountVectorizer(stop_words='english')  
X = vectorizer.fit_transform(docs)  

# 3. Fit LDA with 2 topics  
lda = LatentDirichletAllocation(n_components=2, random_state=0)  
lda.fit(X)  

# 4. Display top words per topic  
def display_topics(model, feature_names, no_top_words):  
    for topic_idx, topic in enumerate(model.components_):  
        message = "Topic %d: " % (topic_idx + 1)  
        message += " ".join([feature_names[i] for i in topic.argsort()[:-no_top_words - 1:-1]])  
        print(message)  

# Print out the results  
display_topics(lda, vectorizer.get_feature_names_out(), 5)  

# 5. Visualize topic distribution for each document  
topic_values = lda.transform(X)  

# 6. Load user-provided font  
# font_path = "/mnt/data/file-ngwyeoEN29l1M3O1QpdxCwkj"  
# font_prop = font_manager.FontProperties(fname=font_path)  

# 7. Plot  
# for i, doc in enumerate(topic_values):  
#     plt.figure()  # Each chart must be a distinct plot  
#     plt.bar(range(1, len(doc)+1), doc, tick_label=[f"Topic {j+1}" for j in range(len(doc))])  
#     plt.title(f"Document {i+1} Topic Distribution", fontproperties=font_prop)  
#     plt.xlabel("Topics", fontproperties=font_prop)  
#     plt.ylabel("Proportion", fontproperties=font_prop)  
#     plt.xticks(fontproperties=font_prop)  
#     plt.yticks(fontproperties=font_prop)  
#     plt.tight_layout()  
#     plt.show()  
for i, doc in enumerate(topic_values):  
    plt.figure()  # Each chart must be a distinct plot  
    plt.bar(range(1, len(doc)+1), doc, tick_label=[f"Topic {j+1}" for j in range(len(doc))])  
    plt.title(f"Document {i+1} Topic Distribution")  
    plt.xlabel("Topics")  
    plt.ylabel("Proportion")  
    # plt.xticks(fontproperties=font_prop)  
    # plt.yticks(fontproperties=font_prop)  
    plt.tight_layout()  
    plt.show()  
Topic 1: business health sign good profits
Topic 2: cycles trends report news outlets

LDA example 2¶

In [26]:
import pandas as pd
import os
import numpy as np
import jieba
import time
In [27]:
from gensim import corpora
In [28]:
#创建文档-词矩阵 词袋模型
from gensim import corpora
from gensim.models import LdaModel
from gensim.corpora import Dictionary
merged_df = pd.read_excel("cleaned_text_xwlb.xlsx")
# 创建词典
train_set = merged_df['text'].astype(str).apply(lambda x: x.split())  
# 将文本字符串转换为列表
dictionary = corpora.Dictionary(train_set)
# 创建文档-词矩阵 词袋模型
corpus = [dictionary.doc2bow(text) for text in train_set]
# 将 token2id 转换为 DataFrame
token_id_df = pd.DataFrame(list(dictionary.token2id.items()), columns=['Token', 'ID'])
print(token_id_df.head())
  Token  ID
0     。   0
1  一国两制   1
2    一处   2
3    一道   3
4  万众一心   4
In [29]:
# 保存为 Excel 文件
#token_id_df.to_excel(r"C:\Users\10283\Desktop\token_to_id_mapping.xlsx", index=False)
#print("Token to ID mapping 已保存到 token_to_id_mapping.xlsx")
In [30]:
from gensim.models.coherencemodel import CoherenceModel
import matplotlib.pyplot as plt
# 尝试不同的主题数量
num_topics_range = range(2, 6)
perplexity_scores = []
coherence_scores = []
for num_topics in num_topics_range:    
    print(f"\nTrying with {num_topics} topics:")
    # 训练 LDA 模型    
    lda_model = LdaModel(corpus, num_topics=num_topics, id2word=dictionary, passes=20, random_state=1)
    # 计算困惑度    
    perplexity_score = lda_model.log_perplexity(corpus)    
    perplexity_scores.append(perplexity_score)
    # 计算一致性    
    coherence_model = CoherenceModel(model=lda_model, texts=train_set, dictionary=dictionary, coherence='c_v')    
    coherence_score = coherence_model.get_coherence()    
    coherence_scores.append(coherence_score)
Trying with 2 topics:

Trying with 3 topics:

Trying with 4 topics:

Trying with 5 topics:
In [31]:
# 绘制曲线图
plt.figure(figsize=(10, 5))
Out[31]:
<Figure size 1000x500 with 0 Axes>
<Figure size 1000x500 with 0 Axes>
In [32]:
# 绘制困惑度曲线
plt.subplot(1, 2, 1)
plt.plot(num_topics_range, perplexity_scores, marker='o')
plt.title('Perplexity vs. Number of Topics')
plt.xlabel('Number of Topics')
plt.ylabel('Perplexity')
plt.grid(True)
In [33]:
# 绘制一致性曲线
plt.subplot(1, 2, 2)
plt.plot(num_topics_range, coherence_scores, marker='o', color='orange')
plt.title('Coherence vs. Number of Topics')
plt.xlabel('Number of Topics')
plt.ylabel('Coherence')
plt.grid(True)
plt.tight_layout()
plt.show()
In [35]:
#提取主题词
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation
import pandas as pd

merged_df = pd.read_excel(r"cleaned_text_xwlb.xlsx")
# 假设 merged_df['text'] 包含分词后的文本数据
# 使用 CountVectorizer 创建文档-词矩阵
stop_words = ['。', '一道', '中央', '中', '中国', '今年','佳节']

vectorizer = CountVectorizer(max_df=0.95, min_df=2, stop_words=stop_words)  # 可根据需求设置更多参数
X = vectorizer.fit_transform(merged_df['text'].astype(str))
In [36]:
# 创建 LDA 模型,提取6个主题
lda = LatentDirichletAllocation(n_components=5, random_state=42)
lda.fit(X)
Out[36]:
LatentDirichletAllocation(n_components=5, random_state=42)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
LatentDirichletAllocation(n_components=5, random_state=42)
In [37]:
# 提取每个主题的前200个关键词
feature_names = vectorizer.get_feature_names_out()
topic_keywords = {}

for topic_idx, topic in enumerate(lda.components_):
    topic_keywords[f"Topic {topic_idx + 1}"] = [feature_names[i] for i in topic.argsort()[:-201:-1]]  # 每个主题的前200个关键词
In [38]:
# 转换为 DataFrame 以便查看
topic_keywords_df = pd.DataFrame(dict([(k, pd.Series(v)) for k, v in topic_keywords.items()]))
topic_keywords_df
Out[38]:
Topic 1 Topic 2 Topic 3 Topic 4 Topic 5
0 美国 发展 发展 人民 我国
1 表示 合作 建设 社会主义 全国
2 病例 经济 改革 精神 企业
3 俄罗斯 推动 问题 时代 增长
4 国际 关系 推进 同志 北京
... ... ... ... ... ...
195 连续 造福 引导 优秀 陕西
196 谴责 时代 精准 英雄 利用
197 遭到 致力于 村民 坚决 海南
198 航班 带来 需要 能力 环境
199 接种 开幕式 城乡 历史性 演出

200 rows × 5 columns