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