python 使用 lru_cache 缓存代理IP

本文地址:https://www.cnblogs.com/tujia/p/13690973.html

背景:当我们用python写爬虫时,一般会用到代理IP;代理IP一般是有一定有效时间的,每次请求都换IP,有点浪费IP,所以我们需求在IP的有效时间内需要缓存IP,不换IP

前提知识:

1)@lru_cache 装饰器可以在程序运行期间缓存函数返回值,第一次调用函数缓存函数返回值,后面的调用就直接读缓存返回

2)@lru_cache 装饰器会为被装饰的函数创建两个属性(方法):cache_info 和 cache_clear,其中 cache_clear 方法可以清除缓存,重新计算函数

3)了解更多,请看官方文档:https://docs.python.org/zh-cn/3.7/library/functools.html#functools.lru_cache

下面就直接上代码了,红色的地方是重点:

import requests
from bs4 import BeautifulSoup
from functools import lru_cache


# 获取代理ip(可以去芝麻代理注册一个账号,领取免费IP)
# @link http://h.zhimaruanjian.com/getapi/
@lru_cache(maxsize=1)
def getProxies(retry_times=0):
    # 直连IP的api地址
    api_url = 'http://webapi.http.zhimacangku.com/getip?num=1&type=1&pro=&city=0&yys=0&port=1&pack=97108&ts=0&ys=0&cs=0&lb=1&sb=0&pb=4&mr=1&regions='
    # 请求头
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36'}
    try:
        r = requests.get(api_url, headers=headers, timeout=3)
        if r.status_code == 200:
            if r.text.find('{') > -1:
                j = r.json()
                # 请x秒后再试
                if j['code'] == 111:
                    s = int(re.search(r'd', j['msg']).group(0))
                    time.sleep(s)
                # 套餐已用完
                elif j['code'] == 121:
                    return None
            else:
                proxyMeta = 'http://' + r.text.strip()
                return {'http': proxyMeta, 'https': proxyMeta}

        if retry_times < 3:
            retry_times += 1
            return getProxies(retry_times)
    except requests.exceptions.RequestException:
        pass

    if retry_times < 3:
        retry_times += 1
        return getProxies(retry_times)
    else:
        return None


# 获取网页内容
def getContent(url, retry_times=0, use_proxy=True):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36'}

    try:
        proxies = getProxies() if use_proxy else None
        r = requests.get(url, headers=headers, proxies=proxies, timeout=10)
        if r.status_code == 200:
            r.encoding = 'utf-8'
            return r.text
    except requests.exceptions.InvalidProxyURL:
        print('InvalidProxyURL: %s' % str(proxies))
        # 代理异常,清除一下代理缓存,重新获取代理ip
        getProxies.cache_clear()
    except requests.exceptions.ProxyError:
        print('ProxyError: %s' % str(proxies))
        # 代理异常,清除一下代理缓存,重新获取代理ip
        getProxies.cache_clear()
    except requests.exceptions.InvalidURL:
        print('InvalidURL: %s %s' % (url, str(proxies)))
        # URL错误,也有可能是因为代理异常,所以也重新获取一个代理ip
        getProxies.cache_clear()
    except requests.exceptions.Timeout:
        print('TimeoutError: %s' % url)
    except requests.exceptions.RequestException:
        print('RequestException: %s' % url)

    # 代理异常或其他异常时
    if retry_times < 3:
        retry_times += 1
        return getContent(url, retry_times, use_proxy)
    else:
        return ''


if __name__ == '__main__':
    for i in range(3):
        # 看一下三次打印的代理ip是不是一样的
        print(getProxies())
        # 请求一下百度试试
        content = getContent('https://www.baidu.com')
        if content != '':
            soup = BeautifulSoup(content, 'lxml')
            print(soup.title.string)

    print('Finished')

本文地址:https://www.cnblogs.com/tujia/p/13690973.html


 完。

原文地址:https://www.cnblogs.com/tujia/p/13690973.html