爬取百度贴吧热榜信息

一、选题的背景

百度贴吧是一个较大的交流平台,网友们经常会在上面讨论和发表自己的意见,热门榜是网友们讨论最多的话题,我们从这里可以清楚看到当前网友们讨论的最多的话题是什么

二、设计方案

1.爬虫名称:爬取百度贴吧热榜

2.爬取的内容:爬取百度贴吧热榜排名、标题名称、实时热度

3.爬虫设计方案概述:

  1. 找到需要爬取的页面
  2. 查找页面源码
  3. 对源码进行解析,找到标题、热度等信息
  4. 编写代码
  5. 对数据进行持久化存储
  6. 数据清洗
  7. 数据分析

8.技术难点:代码编写需要导入许多的第三方库,对python语言要有一点的基础,要会使用函数,正则表达式,要会对页面进行分析和内容定位

三、实现步骤及代码(60分)

1.找到自己需要爬取的页面,获取url

这里我们选择今日热榜上的百度贴吧热榜板块进行爬取

网址是:https://tophub.today/n/Om4ejxvxEN

 

 

    1.  
         

      进行页面解析,按F12打开开发者模式,点击图中所指图标,选中标题

 

 

  1. 我们可以看到我们需要获取的所有标题和热度在都在属性名为”al”下的子标签a和td中

分析完后就可以进行代码编写

2.爬虫代码编写

 1 #导入爬虫所需要的包
 2 import requests
 3 import bs4
 4 import pandas as pd
 5 from bs4 import BeautifulSoup
 6 import numpy as np
 7 import matplotlib
 8 import seaborn as sns
 9 from matplotlib import pyplot as plt
10 import re
11 from scipy.sparse import data
12 from wordcloud import WordCloud
13 import matplotlib.pyplot as plt
14 from imageio import imread
15 
16 
17 #获取页面url并进行头部伪装
18 #获取页面数据
19 def getHtml(url):
20     #UA伪装
21     headers = {
22         'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62'
23     }
24     html_text = page_text = requests.get(url = url,headers = headers).text
25 return html_text
26 
27 
28 #获取页面数据并进行标签定位
29 #html解析
30 def htmlJs(html_text):
31     soup = BeautifulSoup(html_text,'lxml')
32     return soup
33 #标签定位
34 def getTitle(): #获取标题
35     title_text = htmlJs(getHtml(url)).select('tbody > tr > .al > a')
36     return title_text
37 #获取热度
38 def getRedu():
39     redu = htmlJs(getHtml(url)).select('tbody > tr > td:nth-of-type(3)')
40 return redu
41 
42 
43 #.进行持久化存储
44 if __name__ == '__main__':
45     url = "https://tophub.today/n/Om4ejxvxEN"
46     getHtml(url)
47     biaoti = [] #存放获取到的标题
48     hot = [] #存放获取到的热度信息
49     for tit in getTitle():
50         biaoti.append(tit.text) #将获取到的标题存放在biaoti数组中
51     # print(biaoti)
52     for rd in getRedu():
53         num = re.findall('\d+\.\d+|\d+',rd.text)
54         # print(num)
55         hot.append(num[0])
56     # print(hot)
57 
58     #对数据进行持久化
59     shuju = [] #存储数据
60     print("{:^10}\t{:^40}\t{:^25}".format('排名','标题','热度'))
61     # 将标题和热度存储到列表中
62     for i in range(15):
63         print("{:^10}\t{:^40}\t{:^25}".format(i+1,biaoti[i],hot[i]))
64         shuju.append([i+1,biaoti[i],hot[i]])
65     #将数据存储到表格里
66     df = pd.DataFrame(shuju,columns = ["排名",'标题','热度'])
67      df.to_csv('百度贴吧热搜榜.csv',index = False)
68      print("保存成功!!!")

 

  结果如下

 

 

 

 

数据清洗

1 #数据清洗
2 #导入文件
3     df = pd.DataFrame(pd.read_csv('百度贴吧热搜榜.csv'))
4 #删除无效行列
5 # 删除无效行
6     df.drop('标题',axis = 1,inplace = True)
7     print(df.head(20))

 

 1 #查找重复值 2 #查找重复值 3 print(df.duplicated()) 

 

 

 
   


结果:无重复值

 1 # 删除重复值 2 print(df.drop_duplicates()) 

 

 

 

 

1 #查找是否有空值
2     print(df['标题'].isnull().value_counts())
3     print(df['热度'].isnull().value_counts())

 

 

 

 1 #异常值的观察 2 print(df.describe()) 

 

 


结果:没问题

 1 #查看相关系数 2 print(df.corr()) 

 

 

 

  1. 数据可视化
     1 #散点图
     2     def sandian():
     3         df = pd.DataFrame(pd.read_csv('百度贴吧热搜榜.csv'))
     4         x = df.排名
     5         y = df.热度
     6         plt.xlabel('排名')
     7         plt.ylabel('热度')
     8         plt.scatter(x,y,color="red",label ="",s = 50)
     9         plt.title("排名与热度的散点图")
    10         plt.legend(loc='best')
    11         plt.show()
    12     sandian()

     

     

     1 #扇形图
     2 def shanxing():
     3     x = df.排名
     4     y = df.热度
     5     name = [x[0],x[1],x[2],x[3],x[4]]
     6     math = [y[0],y[1],y[2],y[3],y[4]]
     7     explode=[0.1,0.1,0.1,0.1,0.1]
     8     plt.pie(math,labels=name,colors=["r","g","c","b","y"],explode=explode)
     9     plt.axis("equal")
    10     plt.title("百度贴吧热板扇形图")
    11     plt.show()
    12 shanxing()

     

     

     

     

     1 #折线图
     2 #排名与热度的折线图
     3     def zhexian():
     4         x = df.排名
     5         y = df.热度
     6         plt.xlabel("排名")
     7         plt.ylabel("热度")
     8         plt.plot(x, y, color = "green", label = "折线")
     9         plt.title("排名与热度的折线图")
    10         plt.legend()
    11         plt.show()
    12     zhexian()

     

     

    1 #线性关系图
    2     def xianxing():
    3         sns.lmplot(x = "排名", y = "热度", data = df)
    4         plt.show()
    5     xianxing()

     

     

     1  # 回归直线的图
     2     def huigui():
     3         # x,y为回归直线的排名和点击数
     4         x = df.排名
     5         y = df.热度
     6         # X,Y为散点图的
     7         X = df.排名
     8         Y = df.热度
     9         # 先定义所需要的数据
    10         x_i2 = 0
    11         x_i = 0
    12         y_i = 0
    13         # 计算出x,y的均值用mean()
    14         q = x.mean()
    15         w = y.mean()
    16         for i in range(15):
    17             x_i2 = x_i + x[i] * x[i]
    18             x_i = x_i + x[i]
    19             y_i = y_i + y[i]
    20         # 运用回归直线的公式计算出所需要的值
    21         # 分子
    22         m_1 = x_i * y_i - 15 * q * w
    23         # 分母
    24         m_2 = x_i2 - 15 * q * q
    25         # 斜率
    26         k = m_1 / m_2
    27         # 截距
    28         b = w - q * k
    29         x = np.linspace(0, 15)
    30         y = k * x + b
    31         print("斜率k=", k, "截距b=", b)
    32         plt.figure(figsize = (6, 4))
    33         plt.xlabel('排名')
    34         plt.ylabel('点击数')
    35         plt.scatter(X, Y, color = "green", label = "散点", linewidth = 2)
    36         plt.plot(x, y, color = "blue", label = "回归直线")
    37         plt.title("回归直线图")
    38         plt.legend()
    39         plt.show()
    40     huigui()

     

     

    #绘制单核密度图
            sns.kdeplot(df['热度'])

     

     

    1 #绘制盒图
    2 def box():
    3     plt.title('热度与排名盒图')
    4     sns.boxplot(x='排名',y='热度', data=df)
    5 box()

     

     

    1 #绘制条形图
    2 def bar():
    3     df = pd.DataFrame(pd.read_csv(('百度贴吧热搜榜.csv')))
    4     plt.bar(df.排名,df.热度,width = 0.5,align = 'center',color = 'r')
    5     plt.title("条形图")
    6     plt.show()
    7 # bar()

     

     

     1 9.    绘制标题词云图
     2 #绘制词云图
     3 def worldCold():
     4     text = ''
     5     for line in df['标题']:
     6        text += line
     7     # 使用jieba模块将字符串分割为单词列表
     8     cut_text = ' '.join(jieba.cut(text))
     9 
    10     color_mask = imread('白色.jpg')  #设置背景图
    11     cloud = WordCloud(
    12         background_color = 'white',
    13         # 对中文操作必须指明字体
    14         font_path=r'simfang.ttf',
    15         mask = color_mask,
    16         max_words = 50,
    17         max_font_size = 200
    18         ).generate(cut_text)
    19 
    20     # 保存词云图片
    21     cloud.to_file('word_cloud.jpg')
    22     plt.imshow(cloud)
    23     plt.axis('off')
    24     plt.show()
    25 worldCold()

     

     

完整代码

  1 # -*- coding: utf-8 -*-
  2 
  3 # 导入爬虫所需要的包
  4 
  5 import jieba as jieba
  6 import requests
  7 import bs4
  8 import pandas as pd
  9 from bs4 import BeautifulSoup
 10 import numpy as np
 11 import matplotlib
 12 import seaborn as sns
 13 from matplotlib import pyplot as plt
 14 import re
 15 from scipy.sparse import data
 16 from wordcloud import WordCloud
 17 import matplotlib.pyplot as plt
 18 from imageio import imread
 19 
 20 
 21 #获取页面数据
 22 
 23 def getHtml(url):
 24     #UA伪装
 25     headers = {
 26         'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62'
 27     }
 28     #发起requsets请求
 29     response = requests.get(url = url,headers = headers)
 30     #获取页面数据
 31     html_text = response.text
 32     return html_text
 33 
 34 
 35 # html解析
 36 
 37 def htmlJs(html_text):
 38     #使用BeautifulSoup工具对页面进行解析
 39     soup = BeautifulSoup(html_text, 'lxml')
 40     return soup
 41 
 42 
 43 # 标签定位
 44 
 45 def getTitle():  # 获取标题
 46     #标题的位置在tbody标签下的tr标签中,使用select选择器
 47     title_text = htmlJs(getHtml(url)).select('tbody > tr > .al > a')
 48     return title_text
 49 
 50 
 51 # 获取热度
 52 
 53 def getRedu():
 54     # 热度的位置在tbody标签下的tr标签中的第三个td标签内部
 55     redu = htmlJs(getHtml(url)).select('tbody > tr > td:nth-of-type(3)')
 56     return redu
 57 
 58 
 59 if __name__ == '__main__':
 60     url = "https://tophub.today/n/Om4ejxvxEN"
 61     getHtml(url)
 62     # 存放获取到的标题
 63     biaoti = []
 64     # 存放获取到的热度信息
 65     hot = []
 66     # 将获取到的标题存放在biaoti数组中
 67     for tit in getTitle():
 68         biaoti.append(tit.text)
 69     # print(biaoti)
 70     for rd in getRedu():
 71         # 用正则表达式筛选出热度的数字
 72         num = re.findall('\d+\.\d+|\d+', rd.text)
 73         # print(num)
 74         hot.append(num[0])
 75     # print(hot)
 76 
 77     # 对数据进行持久化
 78 
 79     # 存储数据
 80 
 81     shuju = []
 82     print("{:^10}\t{:^40}\t{:^25}".format('排名', '标题', '热度'))
 83     # 将标题和热度存储到列表中
 84     for i in range(15):
 85         print("{:^10}\t{:^40}\t{:^25}".format(i + 1, biaoti[i], hot[i]))
 86         shuju.append([i + 1, biaoti[i], hot[i]])
 87 
 88     # 将数据存储到表格里
 89 
 90     df = pd.DataFrame(shuju, columns = ["排名", '标题', '热度'])
 91     #     df.to_csv('百度贴吧热搜榜.csv',index = False)
 92     #     print("保存成功!!!")
 93 
 94     # 导入文件bar
 95 
 96     # 删除无效效行
 97 
 98     def drop():
 99         #标题是我们数据分析时用不到的,所以可以删除
100         df = pd.DataFrame(pd.read_csv("百度贴吧热搜榜.csv"))
101         drop = df.drop('标题', axis = 1, inplace = True)
102     print(drop)
103     # drop()
104 
105 
106     # 输出清除标题后的结果
107 
108     print(df.head(20))
109 
110 
111     # 查找重复值
112 
113     def duplicate():
114         df = pd.DataFrame(pd.read_csv("百度贴吧热搜榜.csv"))
115         print(df.duplicated())
116     # duplicate()
117 
118 
119     #查找是否有重复值
120 
121     def repeat():
122         df = pd.DataFrame(pd.read_csv("泉州市楼房价格.csv"))
123         print(df.duplicated())
124 
125     # repeat()
126 
127 
128     # 查找是否有空值
129 
130     def isnull():
131         df = pd.DataFrame(pd.read_csv("百度贴吧热搜榜.csv"))
132         print(df['标题'].isnull().value_counts())
133         print(df['热度'].isnull().value_counts())
134     # isnull()
135 
136     # 异常值的观察
137 
138     def outliers():
139         df = pd.DataFrame(pd.read_csv("百度贴吧热搜榜.csv"))
140         print(df.describe())
141 
142     # outliers()
143 
144 
145     # 查看相关系数
146 
147     def correlation():
148         print(df.corr())
149 
150     # correlation()
151 
152 
153     #载入绘图时需要的数字代码
154 
155     plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文标签
156     plt.rcParams['font.serif'] = ['KaiTi']
157     plt.rcParams['axes.unicode_minus'] = False
158 
159 
160     # 散点图
161 
162     def sandian():
163         df = pd.DataFrame(pd.read_csv('百度贴吧热搜榜.csv'))
164         x = df.排名
165         y = df.热度
166         plt.xlabel('排名')
167         plt.ylabel('热度')
168         plt.scatter(x, y, color = "red", label = "", s = 50)
169         plt.title("排名与热度的散点图")
170         plt.legend(loc = 'best')
171         plt.show()
172 
173     # sandian()
174 
175 
176 # 扇形图
177 
178 def shanxing():
179     df = pd.DataFrame(pd.read_csv('百度贴吧热搜榜.csv'))
180     x = df.排名
181     y = df.热度
182     # 前五名的学校名称
183     name = [x[0], x[1], x[2], x[3], x[4]]
184     math = [y[0], y[1], y[2], y[3], y[4]]
185     explode = [0.1, 0.1, 0.1, 0.1, 0.1]
186     plt.pie(math, labels = name, colors = ["r", "g", "c", "b", "y"], explode = explode)
187     plt.axis("equal")
188     plt.title("百度贴吧热板扇形图")
189     plt.show()
190 
191 # shanxing()
192 
193 
194 # 折线图
195 
196 # 排名与热度的折线图
197 
198 def zhexian():
199     df = pd.DataFrame(pd.read_csv('百度贴吧热搜榜.csv'))
200     x = df.排名
201     y = df.热度
202     plt.xlabel("排名")
203     plt.ylabel("热度")
204     plt.plot(x, y, color = "green", label = "折线")
205     plt.title("排名与热度的折线图")
206     plt.legend()
207     plt.show()
208 
209 # zhexian()
210 
211 
212 # 线性关系图
213 
214 def xianxing():
215     df = pd.DataFrame(pd.read_csv(('百度贴吧热搜榜.csv')))
216     sns.lmplot(x = "排名", y = "热度", data = df)
217     plt.show()
218 
219 # xianxing()
220 
221 
222 # 回归直线的图
223 
224 def huigui():
225     df = pd.DataFrame(pd.read_csv(('百度贴吧热搜榜.csv')))
226     # x,y为回归直线的排名和点击数
227     x = df.排名
228     y = df.热度
229     # X,Y为散点图的
230     X = df.排名
231     Y = df.热度
232     # 先定义所需要的数据
233     x_i2 = 0
234     x_i = 0
235     y_i = 0
236     # 计算出x,y的均值用mean()
237     q = x.mean()
238     w = y.mean()
239     for i in range(15):
240         x_i2 = x_i + x[i] * x[i]
241         x_i = x_i + x[i]
242         y_i = y_i + y[i]
243     # 运用回归直线的公式计算出所需要的值
244     # 分子
245     m_1 = x_i * y_i - 15 * q * w
246     # 分母
247     m_2 = x_i2 - 15 * q * q
248     # 斜率
249     k = m_1 / m_2
250     # 截距
251     b = w - q * k
252     x = np.linspace(0, 15)
253     y = k * x + b
254     print("斜率k=", k, "截距b=", b)
255     plt.figure(figsize = (6, 4))
256     plt.xlabel('排名')
257     plt.ylabel('点击数')
258     plt.scatter(X, Y, color = "green", label = "散点", linewidth = 2)
259     plt.plot(x, y, color = "blue", label = "回归直线")
260     plt.title("回归直线图")
261     plt.legend()
262     plt.show()
263 
264 # huigui()
265 
266 # 绘制单核密度图
267 
268 def singleCore():
269     df = pd.DataFrame(pd.read_csv(('百度贴吧热搜榜.csv')))
270     sns.kdeplot(df['热度'])
271 # singleCore()
272 
273 # 绘制盒图
274 
275 def box():
276     df = pd.DataFrame(pd.read_csv(('百度贴吧热搜榜.csv')))
277     plt.title('热度与排名盒图')
278     sns.boxplot(x = '排名', y = '热度', data = df)
279 # box()
280 
281 
282 #绘制条形图
283 
284 def bar():
285     df = pd.DataFrame(pd.read_csv(('百度贴吧热搜榜.csv')))
286     plt.bar(df.排名,df.热度,width = 0.5,align = 'center',color = 'r')
287     plt.title("条形图")
288     plt.show()
289 # bar()
290 
291 #绘制词云图
292 
293 def worldCold():
294     text = ''
295     for line in df['标题']:
296        text += line
297     # 使用jieba模块将字符串分割为单词列表
298     cut_text = ' '.join(jieba.cut(text))
299     
300     color_mask = imread('白色.jpg')  #设置背景图
301     cloud = WordCloud(
302         background_color = 'white',
303         # 对中文操作必须指明字体
304         font_path=r'simfang.ttf',
305         mask = color_mask,
306         max_words = 50,
307         max_font_size = 200
308         ).generate(cut_text)
309     
310     # 保存词云图片
311 
312     cloud.to_file('word_cloud.jpg')
313     plt.imshow(cloud)
314     plt.axis('off')
315     plt.show()

 

四、总结(10分)

描述完成此项目得到哪些有益的结论?是否达到预期的目标?以及要改进的建议?

 

结论:可以较为熟练的运用python知识,学会了如何获取一个网站里自己想要的信息,掌握了爬虫的运行原理和使用。对我在python方面的学习有很大的帮助。

 

预期:达标

 

改进:有些网页的元素较为复杂,或者有相同的属性,导致结果会获得一些冗余的数据,使得数据清洗较为困难。之后会使用xpath解析对获取页面元素的代码进行优化

posted @ 2021-12-28 19:34  canno  阅读(338)  评论(0)    收藏  举报