爬取网站前3_下载限速

来源:互联网 发布:淘宝网店计划书怎么写 编辑:程序博客网 时间:2024/05/22 14:35

如果我们爬取网站的速度过快,就会面临被封禁或是造成服务器过载的风险。为了降低这些风险,我们可以在两次下载之间添加延时(其实在解析robots.txt中一般就会有明确指出 下载限速delay的阈值,我们可以根据这个值进行下载限速的设置),从而对爬虫限速。下面是实现下载限速该功能的代码:

#爬取网站的下载限速功能的类的实现,需要import datetime#Throttle类记录了每个域名上次访问的时间,如果当前时间距离上次访问时间小于指定延时, 则执行睡眠操作#我们可以在每次下载之前调用Throttle对爬虫进行限速。class Throttle:  #爬取网站的下载限速功能的类的实现,每次在download下载前使用    """Add a delay between downloads to the same domain"""    def __init__(self, delay):        self.delay = delay  # value of delay between downloads for each domain        self.domains = {}   # timestamp of when a domain was last accessed记录上次访问的时间,小知识timestamp:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。    def wait(self, url):        domain = urllib.parse.urlparse(url).netloc        last_accessed = self.domains.get(domain)        if self.delay>0 and last_accessed is not None:            sleep_secs = self.delay - (datetime.datetime.now() - last_accessed).seconds            if sleep_secs > 0:                time.sleep(sleep_secs)  #domain has been accessed recently,so need to sleep        self.domains[domain] = datetime.datetime.now()#调用这个下载限速类throttle = Throttle(delay)throttle.wait(url)result = download(url, hearders, proxy=proxy, num_retries=num_retries)

将下载限速功能集成到之前的链接爬虫,有如下代码:

import urllib.requestimport urllib.error import re #正则表达式import urllib.parse #将url链接从相对路径(浏览器可懂但python不懂)转为绝对路径(python也懂了)import urllib.robotparser #爬取数据前解析网站robots.txt文件,避免爬取网站所禁止或限制的import datetime  #下载限速功能所需模块def download(url, user_agent = "brain", proxy = None, num_retries = 2):  #下载url网页,proxy是支持代理功能,初始值为None,想要设置就直接传参数即可    print("downloading:",url)    header = {"user-agent": user_agent} #设置用户代理,而不使用python默认的用户代理Python-urllib/3.6    req = urllib.request.Request(url, headers = header)            opener = urllib.request.build_opener()  #为支持代理功能时刻准备着    if proxy:   #如果设置了proxy,那么就进行以下设置以实现支持代理功能        proxy_params = { urllib.parse.urlparse(url).scheme: proxy }        opener.add_handler(urllib.request.ProxyHandler(proxy_params))        response = opener.open(req)            try:        html = urllib.request.urlopen(req).read()    except urllib.error.URLError as e:    #下载过程中出现问题        print("download error:",e.reason)        html = None        if num_retries > 0:     #错误4XX发生在请求存在问题,而5XX错误则发生在服务端存在问题,所以在发生5XX错误时重试下载            if hasattr(e, "code") and 500<= e.code <600:                return  download(url, user_agent, num_retries-1)  # recursively retry 5XX HTTP errors    return html#download("http://example.webscraping.com") #访问正常#download("http://httpstat.us/500") #这个网页测试用,一直是5XXerror#跟踪链接的爬虫#link_crawler()函数传入两个参数:要爬取的网站URL、用于跟踪链接的正则表达式。def link_crawler(seed_url, link_regex):    """先下载 seed_url 网页的源代码,然后提取出里面所有的链接URL,接着对所有匹配到的链接URL与link_regex 进行匹配,如果链接URL里面有link_regex内容,就将这个链接URL放入到队列中,下一次 执行 while crawl_queue: 就对这个链接URL 进行同样的操作。反反复复,直到 crawl_queue 队列为空,才退出函数。"""    crawl_queue = [seed_url]    seen = set(crawl_queue) #有可能链接中互相重复指向,为避免爬取相同的链接,所以我们需要记录哪些链接已经被爬取过(放在集合seen中),若已被爬取过,不再爬取    while crawl_queue:        url = crawl_queue.pop()                rp = urllib.robotparser.RobotFileParser()   #爬取前解析网站robots.txt,检查是否可以爬取网站,避免爬取网站禁止或限制的        rp.set_url("http://example.webscraping.com/robots.txt")        rp.read()        user_agent = "brain"        if rp.can_fetch(user_agent, url):  #解析后发现如果可以正常爬取网站,则继续执行                        #爬取网站的下载限速功能的类的调用,每次在download下载前使用            throttle = Throttle(delay=5) #这里实例网站robots.txt中的delay值为5            throttle.wait(url)            html = download(url)   #html = download(url, hearders, proxy=proxy, num_retries=num_retries)这里可以传所需要的参数                        html = str(html)            #filter for links matching our regular expression            if html == None:                continue            for link in get_links(html):                if re.match(link_regex, link):                    link = urllib.parse.urljoin(seed_url, link) #把提取的相对url路径link(view/178)转化成绝对路径(/view/Poland-178)link                    if link not in seen:  #判断是否之前已经爬取                        seen.add(link) #之前没有的话加在集合中以便后续继续判断                        crawl_queue.append(link) #之前没有的话这个链接可用,放在列表中继续进行爬取        else:            print("Blocked by %s robots,txt" % url)            continue        def get_links(html):    """用来获取一个html网页中所有的链接URL"""    #做了一个匹配模板 webpage_regex,匹配 <a href="xxx"> or <a href='xxx'>这样的字符串,并提取出里面xxx的URL,请注意这里的xxxURL很可能是源码中相对路径,eg view/1 正常访问肯定是打不开的    webpage_regex = re.compile('<a href=["\'](.*?)["\']', re.IGNORECASE)    return re.findall(webpage_regex,html)    #return re.findall('<a[^>]+href=["\'](.*?)["\']', html)也可以这样实现,但没有上面的先编译模板再匹配好class Throttle:  #爬取网站的下载限速功能的类的实现,每次在download下载前使用    """Add a delay between downloads to the same domain"""    def __init__(self, delay):        self.delay = delay  # value of delay between downloads for each domain        self.domains = {}   # timestamp of when a domain was last accessed记录上次访问的时间,小知识timestamp:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。    def wait(self, url):        domain = urllib.parse.urlparse(url).netloc        last_accessed = self.domains.get(domain)        if self.delay>0 and last_accessed is not None:            sleep_secs = self.delay - (datetime.datetime.now() - last_accessed).seconds            if sleep_secs > 0:                time.sleep(sleep_secs)  #domain has been accessed recently,so need to sleep        self.domains[domain] = datetime.datetime.now()#只想找http://example.webscraping.com/index... or http://example.webscraping.com/view...link_crawler("http://example.webscraping.com", "/(index|view)")

原创粉丝点击