思路:查看網頁源碼能夠看出,289個頁面按鈕的的URL的規律很明顯
能夠將這些URL寫入一個test.txt文件。對於每一頁面根據HTML能夠看出,找到table標籤下的table標籤,該table標籤下的全部a標籤就是機場詳細信息的連接
進入機場的詳細信息頁面,查看源碼,發現規律也很強,在table的table下的tbody有機場的詳細信息。tr下的兩個td有對應信息的屬性和值,很容易取出。
整體思路就是:<font color="#00FF00">將全部頁碼連接的URL存入test.txt文件,每次讀取一個頁面的URL(一行)訪問,將該頁面上的機場連接提取出來存入列表,分別訪問列表中的機場詳細信息URL,從中提取出機場詳細信息</font>
<font color="FF0000">因爲某些機場的詳細信息頁面源碼提供的信息並不正確,須要執行js腳本後才能獲得正確的信息。所以選擇selenium+phantomjs組合爬取頁面(selenium是一個測試工具,phantomjs是一個無界面瀏覽器,selenium經過打開phantomjs.exe加載phantomjs瀏覽器),能夠獲取加載js後的HTML頁面</font>
代碼以下
import requests # 發請求的庫
from bs4 import BeautifulSoup # 解析HTML的庫
import json
import time
from selenium import webdriver # 加載瀏覽器的庫
airportInfoList = [] # 保存全部機場詳細信息的列表,元素是字典
siteURL = "https://airportcode.51240.com" # 網站資源URL的共同前綴
def getAirportInfo(PageURL, page): # 獲取每一個頁面的機場列表
try: # 設置異常處理能夠在爬取異常時,將已經爬取的內容寫入文件
browser = webdriver.PhantomJS(executable_path=r'C:\phantomjs\bin\phantomjs') # 加載瀏覽器
response = requests.get(PageURL) # requests請求網頁,這個只是獲取機場的URL列表,不須要加載js,直接requests請求
response.raise_for_status() # 出錯拋異常
response.encoding = response.apparent_encoding
html = response.text
soup = BeautifulSoup(html, 'html.parser') # 解析html文件
tag_as = soup.table.table.find_all('a')
length = str(len(tag_as))
i = 1
for tag_a in tag_as:
airportDetailURL = siteURL + tag_a.attrs['href']
print("第:" + str(page) + "/298 個頁面的第:" + str(i) + "/" + length + "個機場")
getAirportDetailInfo(airportDetailURL, browser) # 爬取一個機場的詳細信息
i = i + 1
# 關閉瀏覽器,瀏覽器每爬取一個頁面上的全部機場後重啓一次
# 這是由於若是不關閉瀏覽器,連續訪問頁面,會致使內存佔用增長(雖然只是在一個標籤頁裏請求資源)
# 我嘗試過打開新的標籤頁,刪除舊的標籤,在新的標籤頁裏請求資源,但內存仍是會增長,只是增長的速度慢了
# 把瀏覽器關了重啓是最穩妥的方法了
# 總共有8662個頁面,若是連續爬取,會把內存撐爆的
browser.quit()
except:
print("從 " + PageURL + "獲取數據失敗")
browser.quit()
return 0
def getAirportDetailInfo(airportDetailURL, browser): # 從獲取的機場列表中獲取每一個機場的詳細信息
try:
time.sleep(3) # 間隔3秒訪問一次,訪問服務器速度太快會被禁的,設置爲1秒或2秒會在訪問100多個頁面後被禁
browser.get(airportDetailURL) # 瀏覽器請求頁面
html = browser.page_source
soup = BeautifulSoup(html, 'html.parser')
tag_trs = soup.table.table.find_all('tr')
airportInfoDict = {}
for tr in tag_trs:
airportInfoDict[tr.td.string] = tr.td.next_sibling.next_sibling.span.string
airportInfoList.append(airportInfoDict)
except:
print("從 " + airportDetailURL + "獲取數據失敗")
return 0
def writeInfoToFile(infoFilepath):
with open(infoFilepath, 'w+', encoding='utf-8') as infoFile:
infoFile.write(json.dumps(airportInfoList, ensure_ascii=False))
def main(): # 讀取機場URL文件,獲取機場列表
infoFilePath = "test.json"
page = 1 # 打印爬取進度用,爬取程序很漫長的,沒有提示信息很恐怖的
with open("test.txt", 'r') as AirportFile:
for PageURL in AirportFile:
print("第:" + str(page) + "/298 個頁面")
getAirportInfo(PageURL, page) # 獲取一個頁面中全部機場詳細信息
page = page + 1
writeInfoToFile(infoFilePath) # 將機場詳細信息列表裏的數據寫入json文件
if __name__ == '__main__':
main()