(一)、選題的背景
對2021世界各國人口數量,人口密度以及人口增長率進行數據分析,對世界排名和人口密度二者之間的關系分析,進行數據分析和可視化。可以讓我們更好的直觀各國人口的變化以及增長率,有利於人民預測各國的人口增長數量和分析各國人口增長所呈現出的增長率同國家、地理、社會因素之間的關系。
(二)、主題式網絡爬蟲設計方案
1.主題式網絡爬蟲名稱
《python爬蟲之爬取世界人口排名》
2.主題式網絡爬蟲爬取的內容與數據特征分析
爬取內容:"世界排名","國家名稱","人口數量","增長率","人口密度"
數據特征分析:"世界排名"、"人口密度"的之間關系整體呈現上升的趨勢,可通過后續繪制直方圖、折線圖等觀察數據的變化情況。
3.主題式網絡爬蟲設計方案概述
實現思路:在瀏覽器 中通過F12訪問網頁源代碼,,分析網站源代碼,找到自己所需要的數據所在的位置,提取數據,對數據進行保存到相同路徑csv文件中,讀取改文件,進行數據清洗,數據模型分析,數據可視化處理,繪制分布圖,用最小二乘法分析兩個變量間的二次擬合方程和繪制擬合曲線。
技術難點:對庫使用和庫中函數的運用,爬取的內容的機構分析處理做數據分析,即求回歸系數,因為標題是文字,無法與數字作比較,需要把標題這一列刪除才可。由於不明原因,輸出結果經常會顯示超出列表范圍。
(三)、主題頁面的結構特征分析(10 分)
1.主題頁面的結構與特征分析
url= 'https://www.phb123.com/city/renkou/rk.html'
通過頁面的結構分析,可以得到各個數據之間的便簽都有關聯的關系,<tr><th width="12%">世界排名</th><th width="30%">國家</th><th width="20%">人口數量</th><th width="12%">增長率</th><th width="26%">人口密度(公里²)</th>這種形式如下圖所示。
2.Htmls 頁面解析
3.節點(標簽)查找方法與遍歷方法
節點如下圖所示:
<td class="xh">1</td>
<td>
<a href="/city/renkou/country_1.html" title="中國" target="_blank" class="cty">
<span class="fl"><img src="https://img.phb123.com/uploads/guoqi/CN.jpg" alt="中國" width="70" height="42"></span>
<p>中國</p>
</a>
</td>
<td>1,411,780,000</td>
<td>0.39%</td>
<td>144.30</td>
</tr><tr>
<td class="xh">2</td>
<td>
<a href="/city/renkou/country_2.html" title="印度" target="_blank" class="cty">
<span class="fl"><img src="https://img.phb123.com/uploads/guoqi/IN.jpg" alt="印度" width="70" height="42"></span>
<p>印度</p>
</a>
</td>
<td>1,354,051,854</td>
<td>1.11%</td>
<td>411.87</td>
</tr><tr>
<td class="xh">3</td>
<td>
<a href="/city/renkou/country_3.html" title="美國" target="_blank" class="cty">
(
(四)、網絡爬蟲程序設計(60 分)
1.數據爬取與采集
1 import requests 2 from bs4 import BeautifulSoup 3 import pandas as pd 4 5 headers = { 6 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' 7 }#爬蟲[Requests設置請求頭Headers],偽造瀏覽器 8 # 核心爬取代碼https://www.phb123.com/city/renkou/rk_9.html 9 listData=[] #定義數組 10 counData=[] #定義數組 11 for i in range(1,10): 12 if i==1: 13 url= 'https://www.phb123.com/city/renkou/rk.html' 14 else: 15 url = 'https://www.phb123.com/city/renkou/rk_%s.html'%i 16 params = {"show_ram":1} 17 response = requests.get(url,params=params, headers=headers) #訪問url 18 soup = BeautifulSoup(response.text, 'html.parser') #獲取網頁源代碼 19 tr = soup.find('table',class_='rank-table').find_all('tr') #.find定位到所需數據位置 .find_all查找所有的tr(表格) 20 # 去除標簽欄 21 for j in tr[1:]: #tr[1:]遍歷第1列到最后一列,表頭為第0列 22 td = j.find_all('td')#td表格 23 rank = td[0].get_text().strip() #世界排名 24 country = td[1].get_text().strip() #國家 25 counData.append(country) 26 number = td[2].get_text().strip() #人口數量 27 growth = td[3].get_text().strip() #增長率 28 density = td[4].get_text().strip() #人口密度 29 listData.append([rank,country,number,growth,density]) 30 31 32 # 存儲結果 33 df = pd.DataFrame(listData,columns=["世界排名","國家名稱","人口數量","增長率","人口密度"]) 34 print(df) 35 df.to_csv('世界人口排名2020.csv',encoding = 'gbk') #保存文件,數據持久化 36 df 37 df.to_csv("世界人口排名2020.csv",index=False)
2.對數據進行清洗和處理
#讀取csv文件 import pandas as pd df = pd.DataFrame(pd.read_csv("世界人口排名2021.csv")) df
df.info() #使用describe查看統計信息 df.describe()
from sklearn.linear_model import LinearRegression X = df.drop("國家名稱", axis = 1) #X是刪除了國家名稱列后的DataFrame X.head()
#統計“數值”一列中空值的個數 df['人口數量'].isnull().value_counts()
#查找重復值 df.duplicated()
3.文本分析(可選):jieba 分詞、wordcloud 的分詞可視化
1 # 3.文本分析(可選):jieba 分詞、wordcloud 的分詞可視化 2 #使用jieba分詞 3 file=open('世界人口排名2021.csv',encoding='utf_8') 4 user_dict=file.read() 5 print(user_dict) 6 #讀取文件,用jieba進行文本分詞並保存文件中 7 asd_excel=open('世界人口排名2021.csv','r',encoding='utf_8').read() 8 #讀取文件,編碼格式utf-8,防止處理中文出錯 9 import jieba.posseg as psg 10 asd_words_with_attr=[(x.word,x.flag)for x in psg.cut(asd_excel) if len(x.word)>=2] 11 #x.word為詞本身,x.flag為詞性 12 print(len(asd_words_with_attr))#輸出 13 with open('cut_words.txt','w+')as f: 14 for x in asd_words_with_attr: 15 f.write('{0}\t{1}\n'.format(x[0],x[1])) 16 #從cut_words.txt中讀取帶詞性的分詞結果列表 17 asd_words_with_attr=[] 18 with open('cut_words.txt','w+')as f: 19 for x in f.readlines(): 20 pair=x.split() 21 asd_words_with_attr.append((pair[0],pair[1])) 22 #stop_attr中存放要過濾掉的詞性列表 23 stop_attr=['vn','n'] 24 #過濾清洗數據,將結果存放在words中 25 words=[x[0]for x in asd_words_with_attr if x[1] not in stop_attr]
4.數據分析與可視化(例如:數據柱形圖、直方圖、散點圖、盒圖、分布圖)
#直方圖 import pandas as pd import numpy as np import matplotlib.pyplot as plt import pandas as pd import warnings plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False filename = "世界人口排名2021.csv" colnames=["世界排名","國家名稱","人口數量","增長率","人口密度"] #skiprows用於指定跳過csv文件的頭部的前幾行(標題等無效數據,否則程序會報錯) df = pd.read_csv(filename,skiprows=1,names=colnames) data=np.array(df['人口密度'][:30]) index=df['世界排行'][:30] s = pd.Series(data,index) s.name='世界人口排名2021' s.plot(kind='bar',title='世界人口排名2021') plt.grid() plt.s #2 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False filename = "世界人口排名2020.csv" colnames=["世界排名","國家名稱","人口數量","增長率","人口密度"] #skiprows用於指定跳過csv文件的頭部的前幾行(標題等無效數據,否則程序會報錯) df = pd.read_csv(filename,skiprows=1,names=colnames) data=np.array(df['人口密度'][1:30]) index=df['國家名稱'][1:30] s = pd.Series(data,index) s.name='世界人口排名2021' s.plot(kind='bar',title='世界人口排名2021') plt.grid() plt.show()
#折線圖 import numpy as np import matplotlib.pyplot as plt import pandas as pd df=pd.read_csv('世界人口排名2021.csv') print(df.head()) x=df["世界排名"][1:30] y=df["人口密度"][1:30] plt.plot(x,y,'o', color='seagreen') plt.plot(x,y,'-', color='indianred') plt.legend(labels=['世界人口排名2021'])#添加圖標 plt.show()
5.根據數據之間的關系,分析兩個變量之間的相關系數,畫出散點圖,並建立變
量之間的回歸方程(一元或多元)。
1 #選擇世界排名以及人口數量兩個特征變量,繪制分布圖,用最小二乘法分析兩個變量間的二次擬合方程和擬合曲線 2 import pandas as pd 3 import matplotlib.pyplot as plt 4 filename = '世界人口排名2021.csv' 5 colnames=["世界排名","國家名稱","人口數量","增長率","人口密度"] 6 df = pd.read_csv(filename,skiprows=1,names=colnames) 7 X = df["世界排名"][1:20] 8 Y = df["人口密度"][1:20] 9 def A(): 10 plt.scatter(X,Y,color="blue",linewidth=2) 11 plt.title("總情況",color="blue") 12 plt.grid() 13 plt.show() 14 def B(): 15 plt.scatter(X,Y,color="green",linewidth=2) 16 plt.title("總情況",color="blue") 17 plt.grid() 18 plt.show() 19 def func(p,x): 20 a,b,c=p 21 return a*x*x+b*x+c 22 def error(p,x,y): 23 return func(p,x)-y 24 def main(): 25 plt.figure(figsize=(10,6)) 26 p0=[0,0,0] 27 Para = leastsq(error,p0,args=(X,Y)) 28 a,b,c=Para[0] 29 print("a=",a,"b=",b,"c=",c) 30 plt.scatter(X,Y,color="blue",linewidth=2) 31 x=np.linspace(0,20,20) 32 y=a*x*x+b*x+c 33 plt.plot(x,y,color="blue",linewidth=2,) 34 plt.title("總情況") 35 plt.grid() 36 plt.show() 37 print(A()) 38 print(B()) 39 print(main())
6.數據持久化
#6.數據持久化 df = pd.DataFrame(listData,columns=["世界排名","國家名稱","人口數量","增長率","人口密度"]) df.to_csv('世界人口排名2020.csv',encoding = 'gbk') #保存文件,數據持久化
7.將以上各部分的代碼匯總,附上完整程序代碼
1 # 1.數據爬取與采集 2 import requests 3 from bs4 import BeautifulSoup 4 import pandas as pd 5 6 headers = { 7 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' 8 }#爬蟲[Requests設置請求頭Headers],偽造瀏覽器 9 # 核心爬取代碼https://www.phb123.com/city/renkou/rk_9.html 10 listData=[] #定義數組 11 counData=[] #定義數組 12 for i in range(1,10): 13 if i==1: 14 url= 'https://www.phb123.com/city/renkou/rk.html' 15 else: 16 url = 'https://www.phb123.com/city/renkou/rk_%s.html'%i 17 params = {"show_ram":1} 18 response = requests.get(url,params=params, headers=headers) #訪問url 19 soup = BeautifulSoup(response.text, 'html.parser') #獲取網頁源代碼 20 tr = soup.find('table',class_='rank-table').find_all('tr') #.find定位到所需數據位置 .find_all查找所有的tr(表格) 21 # 去除標簽欄 22 for j in tr[1:]: #tr[1:]遍歷第1列到最后一列,表頭為第0列 23 td = j.find_all('td')#td表格 24 rank = td[0].get_text().strip() #世界排名 25 country = td[1].get_text().strip() #國家 26 counData.append(country) 27 number = td[2].get_text().strip() #人口數量 28 growth = td[3].get_text().strip() #增長率 29 density = td[4].get_text().strip() #人口密度 30 listData.append([rank,country,number,growth,density]) 31 32 33 # 存儲結果 34 df = pd.DataFrame(listData,columns=["世界排名","國家名稱","人口數量","增長率","人口密度"]) 35 print(df) 36 df.to_csv('世界人口排名2020.csv',encoding = 'gbk') #保存文件,數據持久化 37 df 38 df.to_csv("世界人口排名2020.csv",index=False) 39 40 # 2.對數據進行清洗和處理 41 42 #讀取csv文件 43 df = pd.DataFrame(pd.read_csv("世界人口排名2021.csv")) 44 45 df.head() 46 df.shape 47 df.info() 48 #使用describe查看統計信息 49 df.describe() 50 51 from sklearn.linear_model import LinearRegression 52 X = df.drop("國家名稱", axis = 1) #X是刪除了國家名稱列后的DataFrame 53 Y = df.drop("人口數量", axis = 1) 54 Y.head() 55 X.head() 56 #統計“數值”一列中空值的個數 57 df['人口數量'].isnull().value_counts() 58 #查找重復值 59 df.duplicated() 60 61 # 3.文本分析(可選):jieba 分詞、wordcloud 的分詞可視化 62 #使用jieba分詞 63 file=open('世界人口排名2021.csv',encoding='utf_8') 64 user_dict=file.read() 65 print(user_dict) 66 #讀取文件,用jieba進行文本分詞並保存文件中 67 asd_excel=open('世界人口排名2021.csv','r',encoding='utf_8').read() 68 #讀取文件,編碼格式utf-8,防止處理中文出錯 69 import jieba.posseg as psg 70 asd_words_with_attr=[(x.word,x.flag)for x in psg.cut(asd_excel) if len(x.word)>=2] 71 #x.word為詞本身,x.flag為詞性 72 print(len(asd_words_with_attr))#輸出 73 with open('cut_words.txt','w+')as f: 74 for x in asd_words_with_attr: 75 f.write('{0}\t{1}\n'.format(x[0],x[1])) 76 #從cut_words.txt中讀取帶詞性的分詞結果列表 77 asd_words_with_attr=[] 78 with open('cut_words.txt','w+')as f: 79 for x in f.readlines(): 80 pair=x.split() 81 asd_words_with_attr.append((pair[0],pair[1])) 82 #stop_attr中存放要過濾掉的詞性列表 83 stop_attr=['vn','n'] 84 #過濾清洗數據,將結果存放在words中 85 words=[x[0]for x in asd_words_with_attr if x[1] not in stop_attr] 86 87 # 4.數據分析與可視化(例如:數據柱形圖、直方圖、散點圖、盒圖、分布圖) 88 #4.1世界人口排名2021中世界排行和人口密度的 89 #柱狀圖 90 import pandas as pd 91 import numpy as np 92 import matplotlib.pyplot as plt 93 import pandas as pd 94 import warnings 95 plt.rcParams['font.sans-serif'] = ['SimHei'] 96 plt.rcParams['axes.unicode_minus'] = False 97 filename = "世界人口排名2021.csv" 98 colnames=["世界排名","國家名稱","人口數量","增長率","人口密度"] 99 #skiprows用於指定跳過csv文件的頭部的前幾行(標題等無效數據,否則程序會報錯) 100 df = pd.read_csv(filename,skiprows=1,names=colnames) 101 data=np.array(df['人口密度'][:30]) 102 index=df['世界排名'][:30] 103 s = pd.Series(data,index) 104 s.name='世界人口排名2021' 105 s.plot(kind='bar',title='世界人口排名2021') 106 plt.grid() 107 plt.show() 108 109 #2 110 plt.rcParams['font.sans-serif'] = ['SimHei'] 111 plt.rcParams['axes.unicode_minus'] = False 112 113 filename = "世界人口排名2020.csv" 114 colnames=["世界排名","國家名稱","人口數量","增長率","人口密度"] 115 #skiprows用於指定跳過csv文件的頭部的前幾行(標題等無效數據,否則程序會報錯) 116 df = pd.read_csv(filename,skiprows=1,names=colnames) 117 118 data=np.array(df['人口密度'][1:30]) 119 index=df['國家名稱'][1:30] 120 s = pd.Series(data,index) 121 s.name='世界人口排名2021' 122 123 s.plot(kind='bar',title='世界人口排名2021') 124 plt.grid() 125 plt.show() 126 127 #折線圖 128 import numpy as np 129 import matplotlib.pyplot as plt 130 import pandas as pd 131 df=pd.read_csv('世界人口排名2021.csv') 132 print(df.head()) 133 x=df["世界排名"][1:30] 134 y=df["人口密度"][1:30] 135 plt.plot(x,y,'o', color='seagreen') 136 plt.plot(x,y,'-', color='indianred') 137 plt.legend(labels=['世界人口排名2021'])#添加圖標 138 plt.show() 139 140 # 直方圖 141 import seaborn as sns 142 plt.figure(figsize=(10,10)) 143 plt.suptitle('世界人口排名2021的直方圖',fontsize=20) 144 plt.xticks(fontsize=20) 145 plt.yticks(fontsize=20) 146 plt.xlabel("世界排行",fontsize=20) 147 sns.distplot(df["人口密度"]) 148 plt.grid() 149 plt.show() 150 151 #盒圖 152 plt.xlabel("世界排名") 153 plt.ylabel("人口密度") 154 sns.boxplot(x='世界排名',y='人口密度',data=df) 155 156 # 散點圖 157 import pandas as pd 158 import numpy as np 159 import matplotlib.pyplot as plt 160 import pandas as pd 161 plt.rcParams['font.sans-serif'] = ['SimHei'] 162 plt.rcParams['axes.unicode_minus'] = False 163 filename = '世界人口排名2021.csv' 164 colnames=["世界排名","國家名稱","人口數量","增長率","人口密度"] 165 #skiprows用於指定跳過csv文件的頭部的前幾行(標題等無效數據,否則程序會報錯) 166 df = pd.read_csv(filename,skiprows=1,names=colnames) 167 plt.scatter(df["世界排名"][:20],df["人口密度"][:20],alpha = 0.6) 168 plt.title("世界人口排名2021") 169 plt.grid() 170 plt.show() 171 172 # “世界人口排名2020“中人口數量和增長率之間的散點圖 173 import pandas as pd 174 import numpy as np 175 import matplotlib.pyplot as plt 176 import pandas as pd 177 plt.rcParams['font.sans-serif'] = ['SimHei'] 178 plt.rcParams['axes.unicode_minus'] = False 179 filename = '世界人口排名2021.csv' 180 colnames=["世界排名","國家名稱","人口數量","增長率","人口密度"] 181 #skiprows用於指定跳過csv文件的頭部的前幾行(標題等無效數據,否則程序會報錯) 182 df = pd.read_csv(filename,skiprows=1,names=colnames) 183 plt.scatter(df["人口數量"][1:15],df["增長率"][1:15],alpha = 0.6) 184 plt.title("世界人口排名2021") 185 plt.grid() 186 plt.show() 187 188 #散點圖 189 # 用來正常顯示中文標簽 190 plt.rcParams['font.sans-serif'] = ['SimHei'] 191 # 用來正常顯示負號 192 plt.rcParams['axes.unicode_minus'] = False 193 #x,y軸 194 plt.xlabel("世界排名") 195 plt.ylabel("人口密度") 196 sns.regplot(x='世界排名',y='人口密度',data=df,color='r') 197 # kind='hex' 198 sns.jointplot(x="世界排名",y="人口密度",data=df,kind='hex') 199 # kind='kde' 200 sns.jointplot(x="世界排名",y="人口密度",data=df,kind="kde",space=0,color='g') 201 #盒圖 202 plt.xlabel("世界排名") 203 plt.ylabel("人口密度") 204 sns.boxplot(x='世界排名',y='人口密度',data=df) 205 206 #分布圖 207 sns.jointplot(df["世界排名"][:20],df["人口密度"][:20]) 208 209 #回歸圖 210 fig,axes=plt.subplots(2,2) 211 #1.默認繪圖效果 212 sns.regplot(x='世界排名',y='人口密度',data=df,ax=axes[0][0]) 213 #2.ci參數可以控制是否顯示置信區間 214 sns.regplot(x='世界排名',y='人口密度',data=df,ci=None,ax=axes[0][1]) 215 #3.mark參數可以設置數據點格式,color參數可以設置顏色 216 sns.regplot(x='世界排名',y='人口密度',data=df,color='g',marker='*',ax=axes[1][0]) 217 #4.fit_reg參數可以控制是否顯示擬合的直線 218 sns.regplot(x='世界排名',y='人口密度',data=df,color='g',marker='+',fit_reg=False,ax=axes[1][1]) 219 220 #5選擇世界排名以及人口數量兩個特征變量,繪制分布圖,用最小二乘法分析兩個變量間的二次擬合方程和擬合曲線 221 import pandas as pd 222 import matplotlib.pyplot as plt 223 filename = '世界人口排名2021.csv' 224 colnames=["世界排名","國家名稱","人口數量","增長率","人口密度"] 225 df = pd.read_csv(filename,skiprows=1,names=colnames) 226 X = df["世界排名"][1:20] 227 Y = df["人口密度"][1:20] 228 def A(): 229 plt.scatter(X,Y,color="blue",linewidth=2) 230 plt.title("總情況",color="blue") 231 plt.grid() 232 plt.show() 233 def B(): 234 plt.scatter(X,Y,color="green",linewidth=2) 235 plt.title("總情況",color="blue") 236 plt.grid() 237 plt.show() 238 def func(p,x): 239 a,b,c=p 240 return a*x*x+b*x+c 241 def error(p,x,y): 242 return func(p,x)-y 243 def main(): 244 plt.figure(figsize=(10,6)) 245 p0=[0,0,0] 246 Para = leastsq(error,p0,args=(X,Y)) 247 a,b,c=Para[0] 248 print("a=",a,"b=",b,"c=",c) 249 plt.scatter(X,Y,color="blue",linewidth=2) 250 x=np.linspace(0,20,20) 251 y=a*x*x+b*x+c 252 plt.plot(x,y,color="blue",linewidth=2,) 253 plt.title("總情況") 254 plt.grid() 255 plt.show() 256 print(A()) 257 print(B()) 258 print(main()) 259 260 #6.數據持久化 261 df = pd.DataFrame(listData,columns=["世界排名","國家名稱","人口數量","增長率","人口密度"]) 262 df.to_csv('世界人口排名2020.csv',encoding = 'gbk') #保存文件,數據持久化
(五)、總結(10 分)
1.經過對主題數據的分析與可視化,可以得到哪些結論?是否達到預期的目標?
通過對數據進行可視化分析發現,在世界人口數量排名居中的國家人口密度相較於排名靠前或靠后的國家更高一點,這種結果可能與各個國家的面積和人口增長率相關,人口數量排名越靠前的國家其增長率越高。
2.在完成此設計過程中,得到哪些收獲?以及要改進的建議?
通過這次的課程設計,更好的鞏固了我們所學習的知識,除此之外還了解了許多課堂之外的知識。讓我們學會懂得利用網絡來為自己解惑。讓我們掌握Python基本概念、編程思想以及程序設計技術,在完成課程的學習后能夠更加熟練地綜合應用Python技術,提高我們自身程序設計水平和計算機應用能力。