(一)代碼1(link_crawler()和get_links()實現鏈接爬蟲)
1 import urllib.request as ure 2 import re 3 import urllib.parse 4 from delayed import WaitFor 5 #下載網頁並返回HTML(動態加載的部分下載不了) 6 def download(url,user_agent='Socrates',num=2): 7 print('下載:'+url) 8 #設置用戶代理 9 headers = {'user_agent':user_agent} 10 request = ure.Request(url,headers=headers) 11 try: 12 #下載網頁 13 html = ure.urlopen(request).read() 14 except ure.URLError as e: 15 print('下載失敗'+e.reason) 16 html=None 17 if num>0: 18 #遇到5XX錯誤時,遞歸調用自身重試下載,最多重復2次 19 if hasattr(e,'code') and 500<=e.code<600: 20 return download(url,num-1) 21 return html 22 #seed_url傳入一個url 23 #link_regex傳入一個正則表達式 24 #函數功能:提取和link_regex匹配的所有網頁鏈接並下載 25 def link_crawler(seed_url, link_regex): 26 html = download(seed_url) 27 crawl_queue = [] 28 #迭代get_links()返回的列表,將匹配正則表達式link_regex的鏈接添加到列表中 29 for link in get_links(html): 30 if re.match(link_regex, link): 31 #拼接https://www.cnblogs.com/ 和 /cate/... 32 link = urllib.parse.urljoin(seed_url, link) 33 #不在列表中才添加 34 if link not in crawl_queue: 35 crawl_queue.append(link) 36 #調用WaitFor的wait()函數,下載限速,間隔小於2秒則等待,直到時間等於2秒才繼續下載(大於則直接繼續下載) 37 waitFor = WaitFor(2) 38 #下載crawl_queue中的所有網頁 39 while crawl_queue: 40 #刪除列表末尾的數據 41 url = crawl_queue.pop() 42 waitFor.wait(url) 43 download(url) 44 #傳入html對象,以列表形式返回所有鏈接 45 def get_links(html): 46 #使用正則表達式提取html中所有網頁鏈接 47 webpage_regex = re.compile('<a[^>]+href=["\'](.*?)["\']',re.IGNORECASE) 48 html = html.decode('utf-8') 49 # 以列表形式返回所有網頁鏈接 50 return webpage_regex.findall(html) 51 52 link_crawler('https://www.cnblogs.com/','/cate/.*')
(二)delayed.py(實現下載限速的類)
1 import urllib.parse 2 import datetime 3 import time 4 class WaitFor(): 5 6 def __init__(self,delay): 7 #delay:希望延遲多長時間(wait()中的處理是以秒為單位) 8 self.delay = delay 9 #用來存放上次下載時間 10 self.domains = dict() 11 12 def wait(self,url): 13 #獲取url netloc屬性的值(即www.cnblogs.com,// 和第一個 /之間的內容) 14 domain = urllib.parse.urlparse(url).netloc 15 #存在鍵值為domain的數據返回value值,否則返回None 16 last_down = self.domains.get(domain) 17 if self.delay >0 and last_down is not None: 18 # 希望延遲時間 - (當前時間-上次下載時間),seconds時間間隔以秒為單位顯示 19 sleep_sec = self.delay-(datetime.datetime.now()-last_down).seconds 20 if sleep_sec > 0: 21 time.sleep(sleep_sec) 22 #將當前時間添加到domains中 23 self.domains[domain] = datetime.datetime.now()