要在 Python/ target=_blank class=infotextkey>Python 中構建一個簡單的網絡爬蟲,我們至少需要一個庫來從 URL 下載 html,還需要一個 HTML 解析庫來提取鏈接。Python 提供標準庫urllib用于發出 HTTP 請求和html.parser用于解析 HTML。僅使用標準庫構建的 Python 爬蟲示例可以在Github上找到。
用于請求和 HTML 解析的標準 Python 庫對開發人員不太友好。其他流行的庫,如requests、品牌為人類的 HTTP 和Beautiful Soup提供了更好的開發者體驗。
如果您想了解更多信息,可以查看有關最佳 Python HTTP 客戶端的指南。
您可以在本地安裝這兩個庫。
pip install requests bs4
可以按照前面的架構圖搭建一個基本的爬蟲。
import logging
from urllib.parse
import urljoin
import requests
from bs4
import BeautifulSoup
logging.basicConfig(
format=
'%(asctime)s %(levelname)s:%(message)s',
level=logging.INFO)
class
Crawler:
def
__init__(
self, urls=[]):
self.visited_urls = []
self.urls_to_visit = urls
def
download_url(
self, url):
return requests.get(url).text
def
get_linked_urls(
self, url, html):
soup = BeautifulSoup(html,
'html.parser')
for link
in soup.find_all(
'a'):
path = link.get(
'href')
if path
and path.startswith(
'/'):
path = urljoin(url, path)
yield path
def
add_url_to_visit(
self, url):
if url
not
in self.visited_urls
and url
not
in self.urls_to_visit:
self.urls_to_visit.Append(url)
def
crawl(
self, url):
html = self.download_url(url)
for url
in self.get_linked_urls(url, html):
self.add_url_to_visit(url)
def
run(
self):
while self.urls_to_visit:
url = self.urls_to_visit.pop(
0)
logging.info(
f'Crawling: {url}')
try:
self.crawl(url)
except Exception:
logging.exception(
f'Failed to crawl: {url}')
finally:
self.visited_urls.append(url)
if __name__ ==
'__main__':
Crawler(urls=[
'https://www.imdb.com/']).run()
上面的代碼定義了一個 Crawler 類,其中包含使用 requests 庫的 download_url、使用 Beautiful Soup 庫的 get_linked_urls 和過濾 URL 的 add_url_to_visit 的幫助方法。要訪問的 URL 和已訪問的 URL 存儲在兩個單獨的列表中。您可以在終端上運行爬蟲。
python crawler.py
爬蟲為每個訪問的 URL 記錄一行。
2020-12-04 18:10:10,737 INFO:Crawling: https://www.imdb.com/
2020-12-04 18:10:11,599 INFO:Crawling: https://www.imdb.com/?ref_=nv_home
2020-12-04 18:10:12,868 INFO:Crawling: https://www.imdb.com/calendar/?ref_=nv_mv_cal
2020-12-04 18:10:13,526 INFO:Crawling: https://www.imdb.com/list/ls016522954/?ref_=nv_tvv_dvd
2020-12-04 18:10:19,174 INFO:Crawling: https://www.imdb.com/chart/top/?ref_=nv_mv_250
2020-12-04 18:10:20,624 INFO:Crawling: https://www.imdb.com/chart/moviemeter/?ref_=nv_mv_mpm
2020-12-04 18:10:21,556 INFO:Crawling: https://www.imdb.com/feature/genre/?ref_=nv_ch_gr
代碼非常簡單,但是在成功爬取一個完整的網站之前,還有許多性能和可用性問題需要解決。
- 爬蟲很慢,不支持并行。從時間戳可以看出,爬取每個 URL 大約需要一秒鐘。每次爬蟲發出請求時,它都會等待請求被解析,并且在兩者之間不做任何工作。
- 下載 URL 邏輯沒有重試機制,URL 隊列不是真正的隊列,在 URL 數量多的情況下效率不高。
- 鏈接提取邏輯不支持通過刪除 URL 查詢字符串參數來標準化 URL,不處理以 # 開頭的 URL,不支持按域?過濾 URL 或過濾對靜態文件的請求。
- 爬蟲不會識別自己并忽略 robots.txt 文件。