Практический пул прокси-серверов асинхронных поисковых роботов Python3 (с открытым исходным кодом)

Python рептилия

Пул прокси-серверов асинхронных искателей, основанный на Python asyncio, предназначен для использования всех преимуществ асинхронной производительности Python.

Рабочая среда

проект используетsanic, асинхронная сетевая структура. Поэтому рекомендуется запускать среду Python как Python3.5+, а Sanic не поддерживает системы Windows, пользователи Windows (такие как я 😄) Рассмотрите возможность использования Ubuntu в Windows.

как пользоваться

Установить Redis

В базе данных проекта используетсяRedis, Redis — это система хранения данных в оперативной памяти с открытым исходным кодом (под лицензией BSD), которую можно использовать в качестве базы данных, кэша и промежуточного программного обеспечения для обмена сообщениями. Поэтому убедитесь, что среда выполнения правильно установила Redis. Пожалуйста, обратитесь к руководству на официальном веб-сайте для получения информации о методе установки.

Скачать исходный код проекта

$ git clone https://github.com/chenjiandongx/async-proxy-pool.git

Установить зависимости

используя требования.txt

$ pip install -r requirements.txt

Использование пипфайла pipenv

$ pipenv install

конфигурационный файл

конфигурационный файлconfig.py, который сохраняет все элементы конфигурации, используемые проектом. Как показано ниже, пользователи могут изменить его в соответствии со своими потребностями. В противном случае вы можете использовать значение по умолчанию.

#!/usr/bin/env python
# coding=utf-8

# 请求超时时间(秒)
REQUEST_TIMEOUT = 15
# 请求延迟时间(秒)
REQUEST_DELAY = 0

# redis 地址
REDIS_HOST = "localhost"
# redis 端口
REDIS_PORT = 6379
# redis 密码
REDIS_PASSWORD = None
# redis set key
REDIS_KEY = "proxies:ranking"
# redis 连接池最大连接量
REDIS_MAX_CONNECTION = 20

# REDIS SCORE 最大分数
MAX_SCORE = 10
# REDIS SCORE 最小分数
MIN_SCORE = 0
# REDIS SCORE 初始分数
INIT_SCORE = 9

# sanic web host
SANIC_HOST = "localhost"
# sanic web port
SANIC_PORT = 3289
# 是否开启 sanic 日志记录
SANIC_ACCESS_LOG = True

# 批量测试数量
VALIDATOR_BATCH_COUNT = 256
# 校验器测试网站,可以定向改为自己想爬取的网站,如新浪,知乎等
VALIDATOR_BASE_URL = "https://httpbin.org/"
# 校验器循环周期(分钟)
VALIDATOR_RUN_CYCLE = 15


# 爬取器循环周期(分钟)
CRAWLER_RUN_CYCLE = 30
# 请求 headers
HEADERS = {
    "X-Requested-With": "XMLHttpRequest",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
}
скопировать код

запустить проект

Запускаем клиент, запускаем сборщик и валидатор

# 可设置校验网站环境变量 set/export VALIDATOR_BASE_URL="https://example.com"
$ python client.py
2018-05-16 23:41:39,234 - Crawler working...
2018-05-16 23:41:40,509 - Crawler √ http://202.83.123.33:3128
2018-05-16 23:41:40,509 - Crawler √ http://123.53.118.122:61234
2018-05-16 23:41:40,510 - Crawler √ http://212.237.63.84:8888
2018-05-16 23:41:40,510 - Crawler √ http://36.73.102.245:8080
2018-05-16 23:41:40,511 - Crawler √ http://78.137.90.253:8080
2018-05-16 23:41:40,512 - Crawler √ http://5.45.70.39:1490
2018-05-16 23:41:40,512 - Crawler √ http://117.102.97.162:8080
2018-05-16 23:41:40,513 - Crawler √ http://109.185.149.65:8080
2018-05-16 23:41:40,513 - Crawler √ http://189.39.143.172:20183
2018-05-16 23:41:40,514 - Crawler √ http://186.225.112.62:20183
2018-05-16 23:41:40,514 - Crawler √ http://189.126.66.154:20183
...
2018-05-16 23:41:55,866 - Validator working...
2018-05-16 23:41:56,951 - Validator × https://114.113.126.82:80
2018-05-16 23:41:56,953 - Validator × https://114.199.125.242:80
2018-05-16 23:41:56,955 - Validator × https://114.228.75.17:6666
2018-05-16 23:41:56,957 - Validator × https://115.227.3.86:9000
2018-05-16 23:41:56,960 - Validator × https://115.229.88.191:9000
2018-05-16 23:41:56,964 - Validator × https://115.229.89.100:9000
2018-05-16 23:41:56,966 - Validator × https://103.18.180.194:8080
2018-05-16 23:41:56,967 - Validator × https://115.229.90.207:9000
2018-05-16 23:41:56,968 - Validator × https://103.216.144.17:8080
2018-05-16 23:41:56,969 - Validator × https://117.65.43.29:31588
2018-05-16 23:41:56,971 - Validator × https://103.248.232.135:8080
2018-05-16 23:41:56,972 - Validator × https://117.94.69.166:61234
2018-05-16 23:41:56,975 - Validator × https://103.26.56.109:8080
...

Запустите сервер, запустите веб-сервис

$ python server.py
[2018-05-16 23:36:22 +0800] [108] [INFO] Goin' Fast @ http://localhost:3289
[2018-05-16 23:36:22 +0800] [108] [INFO] Starting worker [108]

Общая архитектура

Основными модулями проекта являются модуль сканирования, модуль хранения, модуль проверки, модуль планирования и модуль интерфейса.

Он отвечает за обход прокси-сайта и сохранение полученного прокси в базе данных.Инициализационный вес каждого прокси равен INIT_SCORE.

Он инкапсулирует некоторые интерфейсы для операций Redis и предоставляет пулы соединений Redis.

Убедитесь, что IP-адрес прокси-сервера доступен, если прокси-сервер доступен, вес равен +1, а максимальное значение равно MAX_SCORE. Если он недоступен, вес равен -1 до тех пор, пока вес не станет равным 0, чтобы удалить агент из базы данных.

Отвечает за планирование операций сканера и валидатора.

С санит.WEB API.

/

страница приветствия

$ http http://localhost:3289/
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 42
Content-Type: application/json
Keep-Alive: 5

{
    "Welcome": "This is a proxy pool system."
}

/pop

Вернуть прокси случайным образом, с трех попыток.

  1. Попытка вернуть вес MAX_SCORE, который является последним доступным прокси.
  2. Попытки вернуть прокси со случайным весом от (MAX_SCORE -3) до MAX_SCORE.
  3. Попытка вернуть прокси с весом от 0 до MAX_SCORE
$ http http://localhost:3289/pop
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 38
Content-Type: application/json
Keep-Alive: 5

{
    "http": "http://46.48.105.235:8080"
}

/get/<count:int>

Возвращает указанное количество прокси, отсортированных по весу от большего к меньшему.

$ http http://localhost:3289/get/10
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 393
Content-Type: application/json
Keep-Alive: 5

[
    {
        "http": "http://94.177.214.215:3128"
    },
    {
        "http": "http://94.139.242.70:53281"
    },
    {
        "http": "http://94.130.92.40:3128"
    },
    {
        "http": "http://82.78.28.139:8080"
    },
    {
        "http": "http://82.222.153.227:9090"
    },
    {
        "http": "http://80.211.228.238:8888"
    },
    {
        "http": "http://80.211.180.224:3128"
    },
    {
        "http": "http://79.101.98.2:53281"
    },
    {
        "http": "http://66.96.233.182:8080"
    },
    {
        "http": "http://61.228.45.165:8080"
    }
]

/count

Возвращает общее количество всех агентов в пуле агентов.

$ http http://localhost:3289/count
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 15
Content-Type: application/json
Keep-Alive: 5

{
    "count": "698"
}

/count/<score:int>

Возвращает общее количество агентов с указанным весом

$ http http://localhost:3289/count/10
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 15
Content-Type: application/json
Keep-Alive: 5

{
    "count": "143"
}

/clear/<score:int>

Удалить агентов с весом меньше или равным счету

$ http http://localhost:3289/clear/0
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 22
Content-Type: application/json
Keep-Alive: 5

{
    "Clear": "Successful"
}

Расширенный прокси-сканер веб-сайта

Добавьте свой собственный метод сканирования в файл crawler.py.

class Crawler:

    @staticmethod
    def run():
        ...

    # 新增你自己的爬取方法
    @staticmethod
    @collect_funcs      # 加入装饰器用于最后运行函数
    def crawl_xxx():
        # 爬取逻辑

Выбрать другой веб-фреймворк

В этом проекте используется Sanic, но разработчики могут выбрать другие веб-фреймворки в соответствии со своими потребностями.Веб-модули полностью независимы, и замена фреймворка не повлияет на нормальную работу проекта. Требуются следующие шаги.

  1. существуетwebapi.pyЗамените раму.
  2. существуетserver.pyИзмените данные запуска приложения здесь.

Sanic тест производительности

использоватьwrkПроведите стресс-тест сервера. Сравнительный анализ проводился в течение 30 секунд с использованием 12 потоков и 400 одновременных HTTP-соединений.

контрольная работаhttp://127.0.0.1:3289/pop

$ wrk -t12 -c400 -d30s http://127.0.0.1:3289/pop
Running 30s test @ http://127.0.0.1:3289/pop
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   350.37ms  118.99ms 660.41ms   60.94%
    Req/Sec    98.18     35.94   277.00     79.43%
  33694 requests in 30.10s, 4.77MB read
  Socket errors: connect 0, read 340, write 0, timeout 0
Requests/sec:   1119.44
Transfer/sec:    162.23KB

контрольная работаhttp://127.0.0.1:3289/get/10

Running 30s test @ http://127.0.0.1:3289/get/10
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   254.90ms   95.43ms 615.14ms   63.51%
    Req/Sec   144.84     61.52   320.00     66.58%
  46538 requests in 30.10s, 22.37MB read
  Socket errors: connect 0, read 28, write 0, timeout 0
Requests/sec:   1546.20
Transfer/sec:    761.02KB

Производительность неплохая, а потом протестировать без работы Redishttp://127.0.0.1:3289/

$ wrk -t12 -c400 -d30s http://127.0.0.1:3289/
Running 30s test @ http://127.0.0.1:3289/
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   127.86ms   41.71ms 260.69ms   55.22%
    Req/Sec   258.56     92.25   520.00     68.90%
  92766 requests in 30.10s, 13.45MB read
Requests/sec:   3081.87
Transfer/sec:    457.47KB

⭐️Requests/sec: 3081.87

Отключите санитарное ведение журнала, проверьтеhttp://127.0.0.1:3289/

$ wrk -t12 -c400 -d30s http://127.0.0.1:3289/
Running 30s test @ http://127.0.0.1:3289/
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    34.63ms   12.66ms  96.28ms   58.07%
    Req/Sec     0.96k   137.29     2.21k    73.29%
  342764 requests in 30.10s, 49.69MB read
Requests/sec:  11387.89
Transfer/sec:      1.65MB

⭐️Requests/sec: 11387.89

Реальный тест производительности прокси

test_proxy.pyДля тестирования фактической производительности прокси

запустить код

$ cd test
$ python test_proxy.py

# 可设置的环境变量
TEST_COUNT = os.environ.get("TEST_COUNT") or 1000
TEST_WEBSITE = os.environ.get("TEST_WEBSITE") or "https://httpbin.org/"
TEST_PROXIES = os.environ.get("TEST_PROXIES") or "http://localhost:3289/get/20"

Измеренный эффект

httpbin.org/

测试代理: http://localhost:3289/get/20
测试网站: https://httpbin.org/
测试次数: 1000
成功次数: 1000
失败次数: 0
成功率: 1.0
скопировать код

taobao.com

测试代理: http://localhost:3289/get/20
测试网站: https://taobao.com/
测试次数: 1000
成功次数: 984
失败次数: 16
成功率: 0.984
скопировать код

baidu.com

测试代理: http://localhost:3289/get/20
测试网站: https://baidu.com
测试次数: 1000
成功次数: 975
失败次数: 25
成功率: 0.975
скопировать код

zhihu.com

测试代理: http://localhost:3289/get/20
测试网站: https://zhihu.com
测试次数: 1000
成功次数: 1000
失败次数: 0
成功率: 1.0
скопировать код

Видно, что производительность на самом деле очень хорошая, а вероятность успеха очень высока. 😉

Пример практического применения

import random

import requests

# 确保已经启动 sanic 服务
# 获取多个然后随机选一个

try:
    proxies = requests.get("http://localhost:3289/get/20").json()
    req = requests.get("https://example.com", proxies=random.choice(proxies))
except:
    raise

# 或者单独弹出一个

try:
    proxy = requests.get("http://localhost:3289/pop").json()
    req = requests.get("https://example.com", proxies=proxy)
except:
    raise

Яма aiohttp

Весь проект основан на aiohttp, асинхронной сетевой библиотеке.В документации проекта введение в прокси выглядит следующим образом.

Фокус: aiohttp поддерживает прокси HTTP/HTTPS

Но он вообще не поддерживает https-прокси, ну так у него в коде написано.

Выделите: поддерживаются только http-прокси.

Настроение у меня, можно сказать, очень сложное. 😲 Но хорошо работает только http прокси, особого влияния не оказывает, смотрите тестовые данные выше.

эталонный проект

✨ 🍰 ✨

License

MIT ©chenjiandongx