python3爬蟲系列13之find_all爬蟲高考分數線並繪製分析圖(普通版)
1. 前言
之前一篇是
python3爬蟲系列10之使用pymysql+pyecharts讀取Mysql數據可視化分析,裏面採用了pyecharts來進行數據繪圖。
在上一篇文章中,從新介紹了一下
python3爬蟲系列12之lxml+xpath和BeautifulSoup+css selector不同方式tiobe網站爬取,這樣我們以後在爬蟲中,就可以採用搭配的方式。
說的是 使用 lxml+xpath和BeautifulSoup+css selector 不同方式的都可以對網站的信息進行提取。
2. BeautifulSoup的 find(),find_all(),findAll()區別
那麼今天說的內容是關於BeautifulSoup的 find(),find_all() 方法的使用。
區別:find_all()方法的返回的值是包含元素的列表,而 find()方法直接返回的是一個結果。
值得一提的是:有人會在一些老代碼中看到find_all和findAll。
說明:
find_all() 與 findAll() 方法的功能相同。
findAll = find_all # Bs3以上
來源:
在BeautifulSoup版本4中,兩者方法已完全相同。在混合大小寫版本(findAll,findAllNext,nextSibling等)已全部更名。
在新代碼中,您應該使用小寫版本,例如find_all。
好了,廢話少說,搞事情了。
3. BeautifulSoup爬蟲高考分數線並繪製分析圖
今天說這個,是一個關於高考網的爬蟲,歷年高考錄取分數線圖的繪製。
目標網站:http://www.gaokao.com
全國 31 個省份的高考錄取分數線,分別是文理科的一本和二本數據。
網頁分析:
目標地址:
http://www.gaokao.com/sichuan/fsx/
http://www.gaokao.com/beijing/fsx/
http://www.gaokao.com/hunan/fsx/
由上訴地址可以看出來,地區分佈主要是 http://www.gaokao.com/xxxxx/fsx/,
可以看到地址是省份的拼音縮寫。
由此我們可以構造url爲:
url = ‘http://www.gaokao.com/’ + diquPY + ‘/fsx/’
其中diquPY 爲省份的拼音。
其次,在看我們爬去的內容區域:
由table標籤即可查詢到。
所以
爬蟲代碼:
爬蟲代碼如下:
#!/usr/bin/python3
import requests
from bs4 import BeautifulSoup
import pypinyin # 與xpinyin相比,pypinyin更強大。
import time
from pyecharts.globals import ThemeType
from pyecharts import options as opts
from pyecharts.charts import Bar
# 爬蟲目標地址:http://www.gaokao.com/jiangsu/fsx/
# 有反爬,添加一下header
headers = {
'User - Agent': 'Mozilla / 5.0(Windows NT 6.1;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 73.0.3683.103Safari / 537.36'
}
# 爬蟲請求
def yanz(diquname):
diquPY = ''
for i in pypinyin.pinyin(diquname, style=pypinyin.NORMAL):
diquPY += ''.join(i)
#print('漢字轉拼音:',diquPY)
url = 'http://www.gaokao.com/' + diquPY + '/fsx/'
print(url)
response = requests.get(url,headers=headers)
if response.status_code == 200:
response.encoding = 'GBK'
html = response.text
soup = BeautifulSoup(html, 'html.parser')
# # 地區只要a標籤的href屬性
# diqu = soup.find(class_='area_box')
# zzr = diqu.find_all('a')
# for item in zzr:
# diquname = item.text
# # diquhref = item.get('href')
# print(diquname)
print('正在查詢歷年分數線:')
wenke, nianfen = wenkechax(soup) # 文科查詢
like = likechax(soup) # 理科查詢
keshihua(diquname,like,wenke,nianfen)
return wenke,like
else:
print('輸入地區錯誤或請求失敗:', response.status_code)
html = None
return None
# 文科
def wenkechax(soup):
wenke=[]
nianfen =[]
# div1 = soup.select('body > div.wrapper.tp10 > div.widbox690.lt > div.cjArea.tm15')
# h2 = soup.select('div.cjArea.tm15 > h2 > a')[0].text
# h3 = soup.select('div.cjArea.tm15 > h3 ')[0].text
# print(h3)
# table
tables = soup.findAll('table')
tab = tables[0] # 要第一個table
for tr in tab.findAll('tr'):
for th in tr.findAll('th'): # 年份
if th.text !='':
#print(th.text)
nianfen.append(th.text)
for td in tr.findAll("td"): # 分數
tdNum = (td.text).strip() # str對象-除去不規則符號\r\n\t\t\t\t,不除也可以。
#print(tdNum) # 所有的批次都獲取到了。
wenke.append(tdNum)
#print(wenke,type(wenke),len(wenke))
# 爲了好看,只要一二本數據。
print('年份',nianfen)
print('文科',wenke[:12])
print('文科',wenke[12:24])
return wenke,nianfen
# 理科
def likechax(soup):
like = [] # 理科
nianfen = [] # 年份
# h4 = soup.select('div.cjArea.tm15 > h3.blue.ft14.txtC.lkTit ')[0].text
# print(h4)
# table
tables = soup.findAll('table')
tab = tables[1] # 要第二個table
for tr in tab.findAll('tr'):
for th in tr.findAll('th'): # 年份
if th.text !='':
#print(th.text)
nianfen.append(th.text)
for td in tr.findAll('td'): # 分數
#print(td.text)
tdNum = (td.text).strip() # str對象-除去不規則符號\r\n\t\t\t\t,不除也可以。
like.append(tdNum)
# 爲了好看,只要一二本數據。
print('年份', nianfen)
print('理科', like[:12])
print('理科', like[12:24])
return like
# 歷年高考錄取分數線繪圖
def keshihua(diquname,like,wenke,nianfen):
print(like)
# 爲了好看,只要一二本數據。
wenkeYb = wenke[:12]
wenkeEb = wenke[12:24]
likeYb = like[:12]
likeEb = like[12:24]
# 繪圖
c = Bar(init_opts=opts.InitOpts(theme=ThemeType.SHINE))
c.add_xaxis([list(z) for z in zip(nianfen)]) # 年份-記住怎麼讀取出來的!
c.add_yaxis('文科一本',[wenkeYb[i] for i in range(1,len(wenkeYb))]) # 去掉'一本'
c.add_yaxis('理科一本', [likeYb[i] for i in range(1,len(likeYb))])
c.add_yaxis('文科二本', [wenkeEb[i] for i in range(1,len(wenkeEb))])
c.add_yaxis('理科二本',[likeEb[i] for i in range(1,len(likeEb))])
c.set_global_opts(title_opts=opts.TitleOpts(title=diquname +'歷年高考錄取分數線圖',subtitle='2009-2019年'))
c.render(diquname +'歷年高考錄取分數線圖.html')
print(diquname + '歷年高考錄取分數線圖繪製完成。')
if __name__ == '__main__':
start = time.time()
#diquname = '湖南'
diquname = input('請輸入查詢的省份:')
yanz(diquname)
print('爬蟲已完畢,程序結束。')
print("用時: {}".format(time.time() - start))
代碼的相關解釋已經寫在了程序中,主要理解一下find_all()方法的使用。
輸入自己要查的省份。
運行一下,效果:
這裏注意一下,我們用了 12.445056438446045秒的時間來爬完數據的。可以看到速度還是比較低的。數據量不大都這麼慢
需要哪個省份就輸入哪個即可自動生成分析圖:
自動生成-分析圖:
江蘇09年理科沒有數據。
至於分析,需要哪個省就自己去看吧,可以看出湖南最高的文科錄取分數線在2011年出現,583分。
報錯解決
- 轉義字符的去除:
在提取的數據的時候,有一些網頁會出現很多轉義字符。
‘\r\n\t\t\t\t528’, ‘\r\n\t\t\t\t523’, ‘\r\n\t\t\t\t507’
除去這種符號:
解決方法:
tdNum = (td.text).strip() # str對象-除去不規則符號\r\n\t\t\t\t。
-
名字轉拼音:
將漢字轉化成對應的拼音。
diquname = ‘四川’
import pypinyin # 與xpinyin相比,pypinyin更強大。
diquPY = ''
for i in pypinyin.pinyin(diquname, style=pypinyin.NORMAL):
diquPY += ''.join(i)
print('漢字轉拼音:',diquPY)
就會轉爲:
好了,上訴到此結束,實際上本文的重點在於爬蟲速度,下一篇會以本文基礎採用多進程的方式來優化速度。