Как использовать прокси для определенного URL-адреса в пауке Scrapy?

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

Как я могу установить прокси для определенного URL-адреса до отправки запроса паука?

В настоящее время мой паук работает нормально со следующей реализацией:

CoreSpider.py

class CoreSpider(scrapy.Spider):
    name = "final"
    def __init__(self):
        self.start_urls = self.read_url()
        self.rules = (
            Rule(
                LinkExtractor(
                    unique=True,
                ),
                callback='parse',
                follow=True
            ),
        )


    def read_url(self):
        urlList = []
        for filename in glob.glob(os.path.join("/root/Public/company_profiler/seed_list", '*.list')):
            with open(filename, "r") as f:
                for line in f.readlines():
                    url = re.sub('\n', '', line)
                    if "http" not in url:
                        url = "http://" + url
                    # print(url)
                    urlList.append(url)

        return urlList

    def parse(self, response):
        print("URL is: ", response.url)
        print("User agent is : ", response.request.headers['User-Agent'])
        filename = '/root/Public/company_profiler/crawled_page/%s.html' % response.url
        article = Extractor(extractor='LargestContentExtractor', html=response.body).getText()
        print("Article is :", article)
        if len(article.split("\n")) < 5:
            print("Skipping to next url : ", article.split("\n"))
        else:
            print("Continue parsing: ", article.split("\n"))
            ContentHandler_copy.ContentHandler_copy.start(article, response.url)

и settings.py

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    'random_useragent.RandomUserAgentMiddleware': 320
}

Я запускаю паука, вызывая его через скрипт RunSpider.py

RunSpider.py

from CoreSpider import CoreSpider
from scrapy.crawler import  CrawlerProcess
from scrapy.utils.project import get_project_settings

process = CrawlerProcess(get_project_settings())
process.crawl(CoreSpider)
process.start()

Обновление: CoreSpider.py

class CoreSpider(scrapy.Spider):
    name = "final"
    def __init__(self):
        self.start_urls = self.read_url()
        self.rules = (
            Rule(LinkExtractor(unique=True), callback='parse', follow=True, process_request='process_request'),
        )

    def process_request(self, request, spider):
        print("Request is : ", request) ### Not printing anything
        if 'xxx' in request.url:  # <-- set proxy for this URL?
            meta = request.get('meta', {})
            meta.update({'proxy': 'https://159.8.18.178:8080'})
            return request.replace(meta=meta)
        return request
        .......

Я также пытался установить такой прокси в методе process_request, но не удалось.

request.meta['proxy'] = "https://159.8.18.178:8080"

Заранее спасибо.


person Om Prakash    schedule 08.01.2018    source источник


Ответы (3)


Чтобы использовать прокси для каждого запроса, укажите атрибут proxy для meta Request в соответствии с документация. В случае CrawlSpider вам потребуется указать аргумент process_request для Rule. В этом методе выборочно примените вышеуказанное (например, настройку meta['proxy']) на основе URL-адреса запроса и верните измененный запрос с заполненным meta.

EDIT: заменить определение правила

self.rules = (
    Rule(LinkExtractor(unique=True), callback='parse', follow=True),
)

с

self.rules = (
    Rule(LinkExtractor(unique=True), callback='parse', follow=True, process_request='process_request'),
)

и определите новый метод process_request в вашем классе CoreSpider:

def process_request(self, request):
    if 'xxx' in request.url:  # <-- set proxy for this URL?
        meta = request.get('meta', {})
        meta.update({'proxy': 'your_proxy'})
        return request.replace(meta=meta)
    return request

EDIT2: я думаю, что проблема может быть вызвана наличием определений start_urls и rules в конструкторе:

...
def __init__(self):
    self.start_urls = self.read_url()
    self.rules = (
        Rule(LinkExtractor(unique=True), callback='parse', follow=True, process_request='process_request'),
    )
...

Правильный способ — использовать эти атрибуты как атрибуты class, т.е.

class CoreSpider(scrapy.Spider):
    name = "final"
    start_urls = self.read_url()
    rules = (
        Rule(LinkExtractor(unique=True), callback='parse', follow=True, process_request='process_request'),
    )

Что касается start_urls, в случаях, когда вам нужно что-то более сложное (например, чтение URL-адресов из внешнего файла), может быть лучше и читабельнее определить start_requests, чтобы получить Requests.

person Tomáš Linhart    schedule 08.01.2018
comment
Я не понял тебя. Как передать аргумент process_request правилу? Не могли бы вы привести пример? Я пробовал class ProxyMiddleware(object): def process_request(self, request, spider): print("Here in proxy middleware.") request.meta['proxy'] = "proxy:port" в middlewares.py. Но это не работает. - person Om Prakash; 08.01.2018
comment
Это не работает. Я попытался напечатать запрос в методе process_request перед проверкой условия, но он даже ничего не печатает. Возможно, process_request не вызывается для каждого URL-адреса. - person Om Prakash; 08.01.2018
comment
Не могли бы вы отредактировать вопрос и опубликовать исходный код обновления, чтобы я мог проверить? - person Tomáš Linhart; 08.01.2018
comment
Виноват! process_request был переопределен для динамического пользовательского агента для каждого запроса. Я внес туда предложенные изменения и бум! теперь это работает. - person Om Prakash; 05.02.2018

самостоятельный метод. Нет промежуточного программного обеспечения.

urls = [url, url, ..., url]
class TestSpider(scrapy.Spider):
    name = 'test'
    allowed_domains = ['test.com']
    # start_urls = urls  # invalid, override by start_requests

    def start_requests(self):
        for url in urls:
            # handle each individual url with or without proxy
            # if url in ['no1.com', 'no2.com', 'no3.com']:
            if url == 'www.no_proxy.com':
                meta_proxy = '' # do not use proxy for this url
            else:
                meta_proxy = "http://127.0.0.1:8888"
            yield scrapy.Request(url=url, callback=self.parse, meta={'proxy': meta_proxy})

    def parse(self, response):
        title = response.xpath('.//title/text()').extract_first()
        yield {'title': title}

использование:

$scrapy runspider test.py -o test.json -s CONCURRENT_REQUESTS_PER_DOMAIN=100 -s CONCURRENT_REQUESTS=100

Отказ от ответственности:

Я не знаю, замедлит ли это скорость сканирования или нет, так как он повторяет URL-адреса один за другим. На данный момент у меня нет тонн тестовых сайтов. Надеюсь, что кто-то, кто использует этот код, оставит комментарий, чтобы увидеть, что они получили.

person anonymous    schedule 12.05.2018

Я даю вам пример использования прокси с определенным URL-адресом.

link = 'https://www.example.com/'
request = Request(link, callback=self.parse_url)
request.meta['proxy'] = "http://PROXYIP:PROXYPORT"
yield request
person parik    schedule 08.01.2018
comment
Где установить такой прокси в моей реализации. Пожалуйста, посмотрите на вопрос. - person Om Prakash; 08.01.2018
comment
@OmPrakash проверьте это и дайте мне знать, если это поможет вам stackoverflow.com/questions/46567024/ - person parik; 08.01.2018