爬虫的DNS缓存

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_29450455/article/details/78709901

爬虫中的DNS缓存的实现


一、实验背景

在实现爬虫的过程中,需要对域名进行DNS解析,要向DNS服务器发起请求。当爬虫的量达到十万、千万级别时,这一部分的耗时就非常可观了,同时也给服务器增大了复旦。因此需要对其进行优化,使其能实现DNS缓存,不必发起太多请求。

二、实现方法

首先想到的就是修改hosts文件,这样能直接省下向DNS发起请求的时间。但是缺点是无法实时更新,如果域名和IP发生了变化则需要手动更改。若未及时更新,甚至可能导致爬虫没有结果。

于是我们想到的方法就是每次查询之前查询请求的域名是否存在于缓存中,查阅资料后可以得出代码:

import socket

_dnscache = {}#dns缓存list,用来记录域名和对应的IP

def _setDNSCache():

    def igetaddrinfo(*args,**kwargs):

        if args in _dnscache: #查询请求的域名是否在DNS缓存中

            return_dnscache[args]

        else:

            _dnscache[args] = socket.igetaddrinfo(*args,**kwargs)

#调用igetaddrinfo将DNS加入缓存

            return _dnscache[args]

    if not hasattr(socket, 'igetaddrinfo'): 

#将socket类的getddrinfo打一个patch,向已知DNS的方向解析

        socket.igetaddrinfo =socket.getaddrinfo 

        socket.getaddrinfo = igetaddrinfo 

将上述保存为dnscache.py

在要用到DNS缓存的时候,只需要import dnscache,然后_setDNSCache()即可

三、实现实例

实验环境:WIN10+python3.6+requests 2.8.1

在实验开始之前,需要将windows的DNS缓存功能关闭,否则会影响到后续的实现以及时间对比。在命令提示符(管理员)中输入net stop dnscache,重启即可。

以爬取bilibili视频网站的视频标题为例。

因为实现的是静态页面的爬取,观察网页源代码可以发现视频标题是被<h1>标签所闭合。由此利用requests库可得到爬虫的代码。

# coding: utf-8

if __name__ =="__main__":

       import dns_cache

       #dns_cache._setDNSCache() #如果需要的话

       import time

       import requests

       i=0

       f=open("ans_dns.txt",'w')

       number=int(input("How many do youwant to know from no.1?"))

       start1 = time.clock()

       while i<number:

              tem=str(i)

              i=i+1

              url="http://www.bilibili.com/video/av"+tem

              req = requests.post(url).text

              h1_start=req.find('<h1')

              h1_end=req.find('</h1>')

              req=req[h1_start:h1_end]

              start=req.find('title=')+7

              end=req.find('">')-1

              req=req[start:end]

              if (h1_start>0):

                     if.write(req+'\n')

       end1 = time.clock()

       #print(end1-start1)

       times=round(end1-start1,2)

       f.write("This program costs"+str(times)+" seconds")

       f.close()

 

爬虫中并未使用正则表达式,利用requests库所发送的请求是基于urllib3的。爬取过程中发现bilibili视频网站的网页是经过gzip加压的,但是好在requests库中已经将其在.text中解压整合在了一起。如果使用urllib库来打开url,则需要经过以下代码解压:

               from gzip importGzipFile

               from StringIOimport StringIO

def gzip(data):

               buf =StringIO(data)

               f =gzip.GzipFile(fileobj=buf)

               return f.read()


爬取10000条

     无DNS缓存:

     有DNS缓存:

上述两条都与DNS请求所需要的时间吻合的很好,过程中使用wireshark抓包也能看到明显的对比。

无DNS缓存机制的抓包:

有DNS缓存机制的抓包:

四、实验结论

     本次的爬虫DNS缓存的实现思路是请求一个域名时如果本地没有缓存,则调用socket.igetaddrinfo去请求解析;如果有缓存则直接使用缓存中的内容。而实现了DNS缓存的爬虫总体上是要快于普通爬虫的,同时也能降低服务器的负担

五、反思

     在实验的过程中,有DNS缓存的爬虫所用的时间超出无DNS缓存的爬虫的程度并不总是与估计值吻合的很好,猜测原因可能是实程中爬虫所能用到的带宽由于其他程序的波动导致也一直在波动从而使得DNS请求的时间并不稳定。

       此外,本次只爬取了bilibili视频站下的一部分标题,并没有考察爬取不同域的爬虫所受到的影响,应该在不同域上的爬虫有DNS缓存也能加快速度。
展开阅读全文

没有更多推荐了,返回首页