Python: улучшения для вращающегося прокси-сканера - PullRequest
0 голосов
/ 09 мая 2018

Я написал фрагмент кода для ротации прокси для многопоточного сканера, но он выглядит не очень хорошо, и я хочу посмотреть, что можно улучшить.

Что я имел в виду:

1) Сделайте несколько запросов (случайный диапазон) с прокси, затем измените его

2) Если заблокировано, измените прокси (удалите его из списка прокси) и повторите попытку.

3) Если возникает ошибка HTTP, повторите попытку с тем же прокси

4) Если произошла ошибка прокси, измените прокси (удалите его из списка прокси) и повторите попытку.

Обычно это работает довольно прилично, хотя я вижу некоторые проблемы, которые могут появиться:

1) функция make_request вызывает itsel, что в некоторых случаях может привести к бесконечному циклу

2) ошибки прокси не обрабатываются должным образом

Вот мой код:

import requests
import threading
import random
import time
import logging
import os


class Crawler():

    def __init__(self):

        self.user_agents = []
        with open('user_agents.txt', 'r') as inpt:
            for line in inpt:
                if line.strip():
                    self.user_agents.append(line.strip())

        self.proxies = []
        with open('proxies.txt', 'r') as inpt:
            for line in inpt:
                if not line.strip():
                    continue
                self.proxies.append({"http": ''.join(["http://",
                                                      line.strip()]),
                                     "https": ''.join(["https://",
                                                       line.strip()])})

        self.headers = {'User-agent': random.choice(self.user_agents)}
        self.session = requests.Session()
        self.counter = 0
        self.current_proxy = None

        self.lock = threading.Lock()

        self.set_proxy()

    def make_request(self, method, url, **kwargs):
        """Request a page and return its content
        @method - string, POST or GET
        @url - string
        @return: string, HTML page source
                or bytes for binary files
        """
        # make only 10 to 20 requests using a proxy
        with self.lock:
            if self.counter > random.randrange(10, 20):
                self.set_proxy()
            else:
                self.counter += 1

        try:
            if method == 'GET':
                if kwargs.get('download', False):
                    req = self.session.get(url,
                                           headers=self.headers,
                                           stream=True, verify=False)
                    return req.raw
                req = self.session.get(url,
                                       headers=self.headers,
                                       verify=False,
                                       **kwargs)
            else:
                req = self.session.post(url,
                                        headers=self.headers,
                                        verify=False,
                                        **kwargs)
            if req.status_code == 407:
                logging.exception('make_request[Proxy Authentication]')
                os._exit(1)

            if req.encoding not in ['utf8', 'utf-8', None]:
                html = req.content.decode(req.encoding)
            else:
                html = req.text

            if 'Access Denied' in html:
                # website's error message. proxy blocked
                with self.lock:
                    self.set_proxy(remove=True)
                time.sleep(1)
                return self.make_request(method, url, **kwargs)

            else:
                return html

        except requests.exceptions.HTTPError as e:
            if e.response.status_code == 403:
                # access forbidden. proxy blocked
                with self.lock:
                    self.set_proxy(remove_proxy=True)
                time.sleep(1)
                return self.make_request(method, url, **kwargs)

            elif e.response.status_code == 404:
                logging.exception(' '.join([
                                    'make_request[HTTPError]',
                                    url, str(e)]))
                return

            elif e.response.status_code == 429:
                # too many requests. proxy blocked
                with self.lock:
                    self.set_proxy(remove_proxy=True)
                time.sleep(1)
                return self.make_request(method, url, **kwargs)

            else:
                logging.exception(' '.join([
                                    'make_request[unknown HTTPError]',
                                    url, str(e)]))
                return None
        except requests.exceptions.InvalidURL as e:
            logging.exception(' '.join([
                                    'make_request[InvalidURL]',
                                    url, str(e)]))
            return None

        except requests.exceptions.Timeout:
            time.sleep(1)
            return self.make_request(method, url, **kwargs)

        except requests.exceptions.ConnectionError as e:
            # Connection refused
            if '403 Forbidden' in str(e):
                logging.exception('make_requests[403 forbidden]')
                os._exit(1)
            with self.lock:
                self.set_proxy()
            time.sleep(1)
            return self.make_request(method, url, **kwargs)

        except Exception as e:
            logging.exception(' '.join([
                                    'make_request[unknown Exception]',
                                    url, str(e)]))
            return None

    def set_proxy(self, remove_proxy=False):
        """Get a random proxy from the list"""
        if remove_proxy:
            try:
                self.proxies.remove(self.current_proxy)
            except:
                pass

        while True:
            if self.proxies:
                proxy = random.choice(self.proxies)
                if not self.is_alive(proxy):
                    continue

                self.current_proxy = proxy
                self.session = requests.Session()
                self.session.proxies = self.current_proxy
                self.headers = {'User-agent': random.choice(self.user_agents)}
                self.counter = 0
                break

            else:
                logging.exception('EMPTY PROXY LIST')
                os._exit(1)
                break

    def is_alive(self, proxy):
        """Check if a proxy is alive or not
        @proxy - dict
        @return: True if alive, False otherwise
        """

        try:
            requests.get('http://www.google.com',
                         proxies=proxy, timeout=5)
            return True
        except:
            return False

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...