自动爬取网上免费代理实战:接口模块篇

1. 接口模块说明

接口模块篇可以专注于把爬取得来的代理以json格式返回,以供我们的爬虫程序使用,从而避开存在反爬机制的网站。

想到接口开发,想要轻量和简单,选择Python编写的Flask Web应用框架再适合不过了。

2. 代码实现

代码环境:Python 3.9.1

第三方依赖包:flask

import json
from flask import Flask, g
from proxypool.storage.redisclient import redisClient
from flask import jsonify
from proxypool.untils.parse import bytes_convert_string
from proxypool.setting import REDIS_KEY

app = Flask(__name__)


@app.route("/")
def index():
    """
    首页
    访问入口`<host-ip>`
    """
    return "<h2>Index Page</h2>" \
           "<p>For example:</p>" \
           "<p>'<host:port>/random',Get a proxy random</p>" \
           "<p>'<host:port>./proxies',Get all proxy(including unavailable) a proxy format: ip:port,score</p>" \
           "<p>'<host:port>/proxy/<num>',Get <num> proxy(including unavailable)</p>"


@app.route("/random")
def get_proxy():
    """
    随机返回一个代理
    访问入口`<host-ip>/random`

    :return: 从redis中读取代理,如果读取失败则返回`{}`,如果读取成功则返回`{'proxy': proxy}`,比如proxy=59.55.164.6:3256
    """
    g.redis = redisClient() if not hasattr(g, 'redis') else g.redis
    g.proxy = g.redis.random_proxy(redis_key='proxies')
    if g.proxy is not None:
        return jsonify(proxy=g.proxy)
    return {'proxy': {}}


@app.route("/proxies")
@app.route("/proxy/<num>")
def get_count(num=None):
    """
    返回count个代理
    访问入口`<host-ip>/proxy/<count>`,其中count是用户输入的数字,输入多少返回多少,超过redis上限则返回all
    访问入口`<host-ip>/proxies`,返回所有代理
    """
    g.redis = redisClient() if not hasattr(g, 'redis') else g.redis
    all = g.redis.get_count(redis_key=REDIS_KEY)
    if num is None:
        # 当访问http://xxx/proxy时,返回all
        g.count = all
    else:
        # 否则只要输入的num不超过all,输入多少返回多少
        if int(num) > all:
            g.count = all
        else:
            g.count = num
    g.proxies = g.redis.get_all(redis_key=REDIS_KEY, start=0, num=g.count, withscores=True)
    p = {}
    for proxy in g.proxies:
        p[bytes_convert_string(proxy[0])] = str(proxy[1])  # for examples: (b'121.232.148.77:3256', 8.0)
    p = json.dumps(p)
    return jsonify(count=g.count, proxy=p)


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5555)

从上面代码中,看到带@app.route,就是路由,注册一个路径,也是我们常熟悉的接口地址+路径

支持的方式有以下:

  1. <host-port>/ ---->首页
  2. <host-port>/random ---->随机返回一个代理,分数高的优先级最高
  3. <host-port>/proxies ---->获取所有的代理
  4. <host-port>/proxy/<count> ---->获取count条代理

其中<host-port>是主机ip加端口号,如下图使用<host-port>/proxies 获取所有的代理,其中代理按照score分数从低到高排序

image

3. 随机获取一个代理

接下来,从redis中获取一个高分数代理,然后对其测试使用,实现代码如下:

import requests
from loguru import logger


def get_proxy(proxy_url):
    """
    随机获取一个代理
    :return: 返回一个代理,比如:`1.2.4.8:6666`,如果没有找到代理则返回`{}`
    """
    try:
        res = requests.get(proxy_url).json()
        return res.get('proxy', None)
    except ConnectionError:
        logger.error('get proxy error')


def test_proxy(proxy):
    """
    测试一个代理
    
    :proxy: 传入一个代理,比如:`113.93.224.2:3256`
    """
    if not len(proxy):
        logger.error(f'没有获取到代理,请等待...')
    logger.debug(f'获得一个代理:{proxy} 正在测试是否可用...')
    try:
        res = requests.get('http://httpbin.org/get', proxies={'http': f'http://{proxy}'}, timeout=5)
        if res.status_code == 200:
            print(res.text)
            origin = res.json().get('origin')
            proxy_ip = proxy.split(":")[0]
            assert origin == proxy_ip
            logger.success("代理可用", f'{proxy_ip}')
    except Exception as e:
        logger.error(f'代理 {proxy} 失败 {e}')


if __name__ == '__main__':
    proxy_url = 'http://127.0.0.1:5555/random'
    proxy = get_proxy(proxy_url)
    test_proxy(proxy)

测试代理结果如下:

image

参考:https://cuiqingcai.com/7048.html
完整代码:https://github.com/rosaany/proxypool

posted @ 2021-08-03 10:54  Rosaany  阅读(83)  评论(0编辑  收藏  举报