Невозможно использовать прокси один за другим, пока не получится правильный ответ - PullRequest
0 голосов
/ 21 февраля 2019

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

Как я могу разрешить моему сценарию продолжать попытки с разными прокси, пока не будет получен правильный ответ?

Мой сценарийна данный момент:

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

class ProxySpider(scrapy.Spider):
    name = "sslproxies"
    check_url = "https://stackoverflow.com/questions/tagged/web-scraping"
    proxy_link = "https://www.sslproxies.org/"

    def start_requests(self):
        proxylist = self.get_proxies()
        random.shuffle(proxylist)
        proxy_ip_port = next(cycle(proxylist))
        print(proxy_ip_port)       #Checking out the proxy address
        request = scrapy.Request(self.check_url, callback=self.parse,errback=self.errback_httpbin,dont_filter=True)
        request.meta['proxy'] = "http://{}".format(proxy_ip_port)
        yield request

    def get_proxies(self):   
        response = requests.get(self.proxy_link)
        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

    def parse(self, response):
        print(response.meta.get("proxy"))  #Compare this to the earlier one whether they both are the same

    def errback_httpbin(self, failure):
        print("Failure: "+str(failure))

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

PS My intension is to seek any solution the way I've started here.

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Как мы знаем, HTTP-ответ должен пройти через все промежуточное программное обеспечение для достижения методов-пауков.

Это означает, что только запросы с действительными прокси-серверами могут переходить к функциям обратного вызова паука.

Чтобы использовать действительные прокси, мы должны сначала проверить ВСЕ прокси, а затем выбирать только из действительных прокси.

Когда наш ранее выбранный прокси больше не работает- мы помечаем этот прокси как недействительный и выбираем новый из оставшихся действительных прокси в пауке errback.

import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.http.request import Request

class ProxySpider(scrapy.Spider):
    name = "sslproxies"
    check_url = "https://stackoverflow.com/questions/tagged/web-scraping"
    proxy_link = "https://www.sslproxies.org/"
    current_proxy = ""
    proxies = {}

    def start_requests(self):
        yield Request(self.proxy_link,callback=self.parse_proxies)

    def parse_proxies(self,response):

        for row in response.css("table#proxylisttable tbody tr"):
             if "yes" in row.extract():
                 td = row.css("td::text").extract()
                 self.proxies["http://{}".format(td[0]+":"+td[1])]={"valid":False}

        for proxy in self.proxies.keys():
             yield Request(self.check_url,callback=self.parse,errback=self.errback_httpbin,
                           meta={"proxy":proxy,
                                 "download_slot":proxy},
                           dont_filter=True)

    def parse(self, response):
        if "proxy" in response.request.meta.keys():
            #As script reaches this parse method we can mark current proxy as valid
            self.proxies[response.request.meta["proxy"]]["valid"] = True
            print(response.meta.get("proxy"))
            if not self.current_proxy:
                #Scraper reaches this code line on first valid response
                self.current_proxy = response.request.meta["proxy"]
                #yield Request(next_url, callback=self.parse_next,
                #              meta={"proxy":self.current_proxy,
                #                    "download_slot":self.current_proxy})

    def errback_httpbin(self, failure):
        if "proxy" in failure.request.meta.keys():
            proxy = failure.request.meta["proxy"]
            if proxy == self.current_proxy:
                #If current proxy after our usage becomes not valid
                #Mark it as not valid
                self.proxies[proxy]["valid"] = False
                for ip_port in self.proxies.keys():
                    #And choose valid proxy from self.proxies
                    if self.proxies[ip_port]["valid"]:
                        failure.request.meta["proxy"] = ip_port
                        failure.request.meta["download_slot"] = ip_port
                        self.current_proxy = ip_port
                        return failure.request
        print("Failure: "+str(failure))

if __name__ == "__main__":
    c = CrawlerProcess({
        'USER_AGENT': 'Mozilla/5.0',
        'COOKIES_ENABLED': False,
        'DOWNLOAD_TIMEOUT' : 10,
        'DOWNLOAD_DELAY' : 3,
    })
    c.crawl(ProxySpider)
    c.start()
0 голосов
/ 23 февраля 2019

вам нужно написать промежуточное ПО для загрузчика, чтобы установить process_exception ловушку , scrapy вызывает эту ловушку при возникновении исключения.в хуке вы могли бы вернуть новый объект Request с флагом dont_filter=True, чтобы позволить scrapy перепланировать запрос до тех пор, пока он не будет выполнен.

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

, чтобы легко сменить прокси-сервер, вы должны использовать встроенный HttpProxyMiddleware, вместо того, чтобы возиться сenvironment:

request.meta['proxy'] = proxy_address

посмотрите на этот проект в качестве примера.

...