(一)代码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()