美文网首页C#与.net
python爬虫小技巧-IP代理池

python爬虫小技巧-IP代理池

作者: NewForMe | 来源:发表于2018-11-08 16:19 被阅读0次

    有一些网站会设置访问阈值,也就是说,如果一个IP访问速度超过这个阈值,那么网站就会认为,这是一个爬虫程序,而不是用户行为。为了避免远程服务器封锁IP,或者想加快爬取速度,一个可行的方法就是使用代理IP,我们需要做的就是创建一个自己的代理IP池。

    思路:通过免费IP代理网站爬取IP,构建一个容量为100的代理IP池。从代理IP池中随机选取IP,在使用IP之前,检查IP是否可用。如果可用,使用该IP访问目标页面,如果不可用,舍弃该IP。当代理IP池中IP的数量小于20的时候,更新整个代理IP池,即重新从免费IP代理网站爬取IP,构建一个新的容量为100的代理IP池。

    我们可以使用lxml的xpath和Beutifulsoup结合的方法,爬取 西刺代理IP
    所有的IP。当然,也可以使用正则表达式,方法很多。代码如下:

    # -*- coding:UTF-8 -*-
    from bs4 import BeautifulSoup
    import subprocess as sp
    from lxml import etree
    import requests
    import random
    import re
    
    """
    函数说明:获取IP代理
    Parameters:
        page - 高匿代理页数,默认获取第一页
    Returns:
        proxys_list - 代理列表
    """
    def get_proxys(page = 1):
        #requests的Session可以自动保持cookie,不需要自己维护cookie内容
        S = requests.Session()
        #西祠代理高匿IP地址
        target_url = 'http://www.xicidaili.com/nn/%d' % page
        #完善的headers
        target_headers = {'Upgrade-Insecure-Requests':'1',
            'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
            'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Referer':'http://www.xicidaili.com/nn/',
            'Accept-Encoding':'gzip, deflate, sdch',
            'Accept-Language':'zh-CN,zh;q=0.8',
        }
        #get请求
        target_response = S.get(url = target_url, headers = target_headers)
        #utf-8编码
        target_response.encoding = 'utf-8'
        #获取网页信息
        target_html = target_response.text
        #获取id为ip_list的table
        bf1_ip_list = BeautifulSoup(target_html, 'lxml')
        bf2_ip_list = BeautifulSoup(str(bf1_ip_list.find_all(id = 'ip_list')), 'lxml')
        ip_list_info = bf2_ip_list.table.contents
        #存储代理的列表
        proxys_list = []
        #爬取每个代理信息
        for index in range(len(ip_list_info)):
            if index % 2 == 1 and index != 1:
                dom = etree.HTML(str(ip_list_info[index]))
                ip = dom.xpath('//td[2]')
                port = dom.xpath('//td[3]')
                protocol = dom.xpath('//td[6]')
                proxys_list.append(protocol[0].text.lower() + '#' + ip[0].text + '#' + port[0].text)
        #返回代理列表
        return proxys_list
    
    """
    函数说明:检查代理IP的连通性
    Parameters:
        ip - 代理的ip地址
        lose_time - 匹配丢包数
        waste_time - 匹配平均时间
    Returns:
        average_time - 代理ip平均耗时
    """
    def check_ip(ip, lose_time, waste_time):
        #命令 -n 要发送的回显请求数 -w 等待每次回复的超时时间(毫秒)
        cmd = "ping -n 3 -w 3 %s"
        #执行命令
        p = sp.Popen(cmd % ip, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, shell=True)
        #获得返回结果并解码
        out = p.stdout.read().decode("gbk")
        #丢包数
        lose_time = lose_time.findall(out)
        #当匹配到丢失包信息失败,默认为三次请求全部丢包,丢包数lose赋值为3
        if len(lose_time) == 0:
            lose = 3
        else:
            lose = int(lose_time[0])
        #如果丢包数目大于2个,则认为连接超时,返回平均耗时1000ms
        if lose > 2:
            #返回False
            return 1000
        #如果丢包数目小于等于2个,获取平均耗时的时间
        else:
            #平均时间
            average = waste_time.findall(out)
            #当匹配耗时时间信息失败,默认三次请求严重超时,返回平均好使1000ms
            if len(average) == 0:
                return 1000
            else:
                #
                average_time = int(average[0])
                #返回平均耗时
                return average_time
    
    """
    函数说明:初始化正则表达式
    Parameters:
        无
    Returns:
        lose_time - 匹配丢包数
        waste_time - 匹配平均时间
    """
    def initpattern():
        #匹配丢包数
        lose_time = re.compile(u"丢失 = (\d+)", re.IGNORECASE)
        #匹配平均时间
        waste_time = re.compile(u"平均 = (\d+)ms", re.IGNORECASE)
        return lose_time, waste_time
    
    if __name__ == '__main__':
        #初始化正则表达式
        lose_time, waste_time = initpattern()
        #获取IP代理
        proxys_list = get_proxys(1)
    
        #如果平均时间超过200ms重新选取ip
        while True:
            #从100个IP中随机选取一个IP作为代理进行访问
            proxy = random.choice(proxys_list)
            split_proxy = proxy.split('#')
            #获取IP
            ip = split_proxy[1]
            #检查ip
            average_time = check_ip(ip, lose_time, waste_time)
            if average_time > 200:
                #去掉不能使用的IP
                proxys_list.remove(proxy)
                print("ip连接超时, 重新获取中!")
            if average_time < 200:
                break
    
        #去掉已经使用的IP
        proxys_list.remove(proxy)
        proxy_dict = {split_proxy[0]:split_proxy[1] + ':' + split_proxy[2]}
        print("使用代理:", proxy_dict)
    

    可以看到,通过这种方法,很容易的就获得了这100个IP,包括他们的协议、IP和端口号。这里我是用”#”符号隔开,使用之前,只需要spilt()方法,就可以提取出信息。
    已经获取了IP,如何验证这个IP是否可用呢?一种方案是GET请求一个网页,设置timeout超市时间,如果超时服务器没有反应,说明IP不可用。
    上述代码验证IP有效性是用了另一种方法,验证一个IP大约需要3秒左右,使用cmd命令,循环ping IP查看IP的连通性。
    从上面代码可以看出,我制定的规则是,如果丢包数大于2个,则认为ip不能用。ping通的平均时间大于200ms也抛弃。
    这里构建代理IP池和检查IP是否可用,如果你感兴趣也可以将获取的IP放入到数据库中,不过我没这样做,因为感觉免费获取的代理IP,失效很快,随用随取就行。

    如果觉得上述校验IP的方法比较复杂,可以使用以下常规的方法通过请求网站超时处理来验证。代码如下:

    import urllib
    def checkip(ip_list):
    
        for ip in ip_list:
            try:
              proxy_host = "https://" + ip
              proxy_temp = {"https": proxy_host}
              res = urllib.urlopen(url, proxies=proxy_temp).read()
            except Exception as e:
              ip_list.remove(ip)
              continue
        return ip_list
    

    调用

    #1
    url = '爬取链接地址'
    response = requests.get(url,proxies=random.choice(ip_list))
    
    #2
    import random
    #把我们从ip代理网站上得到的ip,用ip地址:端口号的格式存入iplist数组
    iplist = ['XXX.XXX.XXX.XXX:XXXX', 'XXX.XXX.XXX.XXX:XXXX']
    proxies ={'http': random.choice(iplist)}
    
    

    总结

    如果你一直被网站封杀却找不到原因,那么这里有个检查列表,可以帮你诊断一下问题出在哪里。

    首先,检查 JavaScript 。如果你从网络服务器收到的页面是空白的,缺少信息,或其遇到他不符合你预期的情况(或者不是你在浏览器上看到的内容),有可能是因为网站创建页面的 JavaScript 执行有问题。

    检查正常浏览器提交的参数。如果你准备向网站提交表单或发出 POST 请求,记得检查一下页面的内容,看看你想提交的每个字段是不是都已经填好,而且格式也正确。用 Chrome 浏览器的网络面板(快捷键 F12 打开开发者控制台,然后点击“Network”即可看到)查看发送到网站的 POST 命令,确认你的每个参数都是正确的。

    是否有合法的 Cookie?如果你已经登录网站却不能保持登录状态,或者网站上出现了其他的“登录状态”异常,请检查你的 cookie。确认在加载每个页面时 cookie 都被正确调用,而且你的 cookie 在每次发起请求时都发送到了网站上。

    IP 被封禁?如果你在客户端遇到了 HTTP 错误,尤其是 403 禁止访问错误,这可能说明网站已经把你的 IP 当作机器人了,不再接受你的任何请求。你要么等待你的 IP 地址从网站黑名单里移除,要么就换个 IP 地址。如果你确定自己并没有被封杀,那么再检查下面的内容:

    • 确认你的爬虫在网站上的速度不是特别快。快速采集是一种恶习,会对网管的服务器造成沉重的负担,还会让你陷入违法境地,也是 IP 被网站列入黑名单的首要原因。给你的爬虫增加延迟,让它们在夜深人静的时候运行。切记:匆匆忙忙写程序或收集数据都是拙劣项目管理的表现;应该提前做好计划,避免临阵慌乱。

    • 还有一件必须做的事情:修改你的请求头!有些网站会封杀任何声称自己是爬虫的访问者。如果你不确定请求头的值怎样才算合适,就用你自己浏览器的请求头吧。

    • 确认你没有点击或访问任何人类用户通常不能点击或接入的信息。

    • 如果你用了一大堆复杂的手段才接入网站,考虑联系一下网管吧,告诉他们你的目的。试试发邮件到 webmaster@< 域名 > 或 admin@< 域名 >,请求网管允许你使用爬虫采集数据。管理员也是人嘛!

    内容参考:https://blog.csdn.net/c406495762/article/details/72793480

    相关文章

      网友评论

        本文标题:python爬虫小技巧-IP代理池

        本文链接:https://www.haomeiwen.com/subject/yajwxqtx.html