Невозможно получить желаемые результаты, используя предложение try / исключением в рамках scrapy - PullRequest
2 голосов
/ 29 апреля 2019

Я написал скрипт в scrapy, чтобы делать прокси-запросы с использованием вновь сгенерированных прокси методом get_proxies(). Я использовал requests модуль для извлечения прокси для повторного их использования в скрипте. Я пытаюсь разобрать все ссылки на фильмы с его целевой страницы , а затем извлечь название каждого фильма с его целевой страницы . Мой следующий скрипт может использовать ротацию прокси.

Я знаю, что есть более простой способ смены прокси, как описано здесь HttpProxyMiddleware но я все равно хотел бы придерживаться того, что я пытаюсь здесь.

ссылка на сайт

Это моя текущая попытка (она продолжает использовать новые прокси для получения правильного ответа, но каждый раз, когда получает 503 Service Unavailable):

import scrapy
import random
import requests
from itertools import cycle
from bs4 import BeautifulSoup
from scrapy.crawler import CrawlerProcess

def get_proxies():   
    response = requests.get("https://www.us-proxy.org/")
    soup = BeautifulSoup(response.text,"lxml")
    proxy = [':'.join([item.select_one("td").text,item.select_one("td:nth-of-type(2)").text]) for item in soup.select("table.table tbody tr") if "yes" in item.text]
    return proxy

class ProxySpider(scrapy.Spider):
    name = "proxiedscript"
    handle_httpstatus_list = [503]
    proxy_vault = get_proxies()
    check_url = "https://yts.am/browse-movies"

    def start_requests(self):
        random.shuffle(self.proxy_vault)
        proxy_url = next(cycle(self.proxy_vault))
        request = scrapy.Request(self.check_url,callback=self.parse,dont_filter=True)
        request.meta['https_proxy'] = f'http://{proxy_url}'
        yield request

    def parse(self,response):
        print(response.meta)
        if "DDoS protection by Cloudflare" in response.css(".attribution > a::text").get():
            random.shuffle(self.proxy_vault)
            proxy_url = next(cycle(self.proxy_vault))
            request = scrapy.Request(self.check_url,callback=self.parse,dont_filter=True)
            request.meta['https_proxy'] = f'http://{proxy_url}'
            yield request

        else:
            for item in response.css(".browse-movie-wrap a.browse-movie-title::attr(href)").getall():
                nlink = response.urljoin(item)
                yield scrapy.Request(nlink,callback=self.parse_details)

    def parse_details(self,response):
        name = response.css("#movie-info h1::text").get()
        yield {"Name":name}

if __name__ == "__main__":
    c = CrawlerProcess({'USER_AGENT':'Mozilla/5.0'})
    c.crawl(ProxySpider)
    c.start()

Чтобы убедиться, что запрос проксируется, я напечатал response.meta и мог получить результаты, подобные этому {'https_proxy': 'http://142.93.127.126:3128', 'download_timeout': 180.0, 'download_slot': 'yts.am', 'download_latency': 0.237013578414917, 'retry_times': 2, 'depth': 0}.

Поскольку я злоупотребил ссылкой, чтобы проверить, как работает прокси-запрос в scrapy, в данный момент я получаю ошибку 503 Service Unavailable, и я вижу это ключевое слово в ответе DDoS protection by Cloudflare. Тем не менее, я получаю действительный ответ, когда пытаюсь с модулем requests применить ту же логику, что и здесь.

My earlier question: why I can't get the valid response as (I suppose) I'm using proxies in the right way? [solved]

Вопрос о вознаграждении: как я могу определить предложение try/except в моем скрипте, чтобы он пытался использовать разные прокси, как только выдает ошибку соединения с определенным прокси?

Ответы [ 2 ]

4 голосов
/ 29 апреля 2019

Согласно scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware документам источнику )
proxy мета-ключ должен использовать (не https_proxy)

#request.meta['https_proxy'] = f'http://{proxy_url}'  
request.meta['proxy'] = f'http://{proxy_url}'

Поскольку scrapy не получил действительный мета-ключ - ваше приложение для scrapy не использовало прокси

3 голосов
/ 06 мая 2019

Функция start_requests() является просто точкой входа.При последующих запросах вам потребуется повторно передать эти метаданные в объект Request.

Кроме того, ошибки могут возникать на двух уровнях: прокси-сервер и целевой сервер.

. Нам необходимо обрабатывать неправильные коды ответов как прокси-сервера, так и целевого сервера.Ошибки прокси возвращаются промежуточным программным обеспечением в функцию errback.Ответ целевого сервера может быть обработан во время синтаксического анализа от response.status

import scrapy
import random
import requests
from itertools import cycle
from bs4 import BeautifulSoup
from scrapy.crawler import CrawlerProcess


def get_proxies():
    response = requests.get("https://www.us-proxy.org/")
    soup = BeautifulSoup(response.text, "lxml")
    proxy = [':'.join([item.select_one("td").text, item.select_one("td:nth-of-type(2)").text]) for item in
             soup.select("table.table tbody tr") if "yes" in item.text]
    # proxy = ['https://52.0.0.1:8090', 'https://52.0.0.2:8090']
    return proxy


def get_random_proxy(proxy_vault):
    random.shuffle(proxy_vault)
    proxy_url = next(cycle(proxy_vault))
    return proxy_url


class ProxySpider(scrapy.Spider):
    name = "proxiedscript"
    handle_httpstatus_list = [503, 502, 401, 403]
    check_url = "https://yts.am/browse-movies"
    proxy_vault = get_proxies()

    def handle_middleware_errors(self, *args, **kwargs):
        # implement middleware error handling here
        print('Middleware Error')
        # retry request with different proxy
        yield self.make_request(url=args[0].request._url, callback=args[0].request._meta['callback'])

    def start_requests(self):
        yield self.make_request(url=self.check_url, callback=self.parse)

    def make_request(self, url, callback, dont_filter=True):
        return scrapy.Request(url,
                              meta={'proxy': f'https://{get_random_proxy(self.proxy_vault)}', 'callback': callback},
                              callback=callback,
                              dont_filter=dont_filter,
                              errback=self.handle_middleware_errors)

    def parse(self, response):
        print(response.meta)
        try:
            if response.status != 200:
                # implement server status code handling here - this loops forever
                print(f'Status code: {response.status}')
                raise
            else:
                for item in response.css(".browse-movie-wrap a.browse-movie-title::attr(href)").getall():
                    nlink = response.urljoin(item)
                    yield self.make_request(url=nlink, callback=self.parse_details)
        except:
            # if anything goes wrong fetching the lister page, try again
            yield self.make_request(url=self.check_url, callback=self.parse)

    def parse_details(self, response):
        print(response.meta)
        try:
            if response.status != 200:
                # implement server status code handeling here - this loops forever
                print(f'Status code: {response.status}')
                raise
            name = response.css("#movie-info h1::text").get()
            yield {"Name": name}
        except:
            # if anything goes wrong fetching the detail page, try again
            yield self.make_request(url=response.request._url, callback=self.parse_details)


if __name__ == "__main__":
    c = CrawlerProcess({'USER_AGENT': 'Mozilla/5.0'})
    c.crawl(ProxySpider)
    c.start()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...