Невозможно понять правильный путь при использовании индивидуального метода в scrapy

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

Я знаю, что есть библиотека, которая предназначена для использования селена в скрэпи. Однако я не заинтересован в использовании этой библиотеки для этого базового варианта использования.

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

Скрипт вроде работает корректно. Скрипт тоже работает корректно, если выкинуть yield отсюда yield self.parse_from_innerpage(response.urljoin(elem)) и использовать лайк self.parse_from_innerpage(response.urljoin(elem)).

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

Я пробовал с:

import scrapy
from selenium import webdriver
from scrapy.crawler import CrawlerProcess
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class StackoverflowSpider(scrapy.Spider):
    name = "stackoverflow"

    start_urls = ['https://stackoverflow.com/questions/tagged/web-scraping']

    def __init__(self):
        self.driver = webdriver.Chrome()
        self.wait = WebDriverWait(self.driver,15)

    def parse(self, response):
        for elem in response.css(".summary .question-hyperlink::attr(href)").getall():
            yield self.parse_from_innerpage(response.urljoin(elem))

    def parse_from_innerpage(self,link):
        self.driver.get(link)
        elem = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "h1[itemprop='name'] > a")))
        print(elem.text)


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

Ваш метод parse_from_innerpage ничего не возвращает (то есть возвращает None). Вероятно, это приводит к тому, что генератор возвращает много объектов None. Вместо использования печати верните elem.text

Chaos Monkey 27.12.2020 11:13
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
244
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

yield в python используется внутри генератора, чтобы «отказаться» от запуска и вернуть значение.

поэтому здесь метод parse возвращает результат parse_from_innerpage. Однако у parse_from_innerpage нет оператора return, а это значит, что он возвращает None.

Прочтите это из документации по scrapy о том, что scrapy ожидает от паука.

Короче говоря, scrapy использует метод parse в качестве генератора результатов, а затем показывает их вам, когда он перестает работать (кончаются ссылки для очистки). Замените print на возврат, и все должно работать как положено.

Ответ принят как подходящий
def parse_from_innerpage(self,link):
        self.driver.get(link)
        elem = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "h1[itemprop='name'] > a")))
        print(elem.text)

Прежде чем попытаться ответить на ваш вопрос, я хочу добавить небольшое примечание о вашем утверждении print() внутри функции parse_from_innerpage(self, link). Хотя эта тема вызывает споры , лучше возвращать рассматриваемый объект - позже вы можете решить напечатать его, назначив экземпляр класса (и затем вызвав метод) или просто напрямую Class.Method(**args)

Это из пути - давайте решим ваш вопрос:

Должен ли я использовать yield или нет в методе parse, чтобы продолжить текущую реализацию, поскольку они оба работают взаимозаменяемо?

Чтобы ответить на этот вопрос или, вернее, понять ответ, я настоятельно рекомендую обратиться к некоторым качественным ресурсам, чтобы понять концепцию yield. Ниже приведены несколько ссылок для дальнейшего чтения:

По сути, return отправляет указанное значение обратно, yield, с другой стороны, создает последовательность значений, поэтому идеально подходит для повторения полученных значений.


Давайте посмотрим на ваш код:

parse(self, response) method:

def parse(self, response):
        for elem in response.css(".summary .question-hyperlink::attr(href)").getall():
            yield self.parse_from_innerpage(response.urljoin(elem))

Проще говоря, этот метод ожидает некоторые значения от parse_from_innerpage(self, link), поскольку он «выдает» или выполняет итерацию по списку получения. Однако ваш parse_from_innerpage(self,link) ничего не возвращает — посмотрите, нет return оператора!:

def parse_from_innerpage(self,link):
        self.driver.get(link)
        elem = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "h1[itemprop='name'] > a")))
        
        #Use return instead of print()
        print(elem.text)

Поскольку parse_from_innerpage(**args) возвращает None, parse(**args) также ничего не вернет, так как нечего перебирать/возвращать. Следовательно, вы должны заменить print() на return.


Я предлагаю просмотреть Документацию по Scrapy (особенно Scrapy с первого взгляда ), чтобы понять, как именно работает Scrapy и что он ожидает от scrapy.Spider для достижения ваших целей. В основном метод parse(**args) используется в качестве генератора (ссылаясь на уже упомянутый вопрос StackOverflow) для результатов, которые вы хотите получить - когда нет элементов для итерации (он останавливается), он «показывает их вам»:

В обратном вызове синтаксического анализа мы перебираем элементы цитаты с помощью CSS. Selector, создайте словарь Python с извлеченным текстом цитаты и автор, найдите ссылку на следующую страницу и запланируйте другой запрос используя тот же метод синтаксического анализа, что и обратный вызов

... но, как уже упоминалось в вашем случае, parse(**args), к сожалению, получает None из-за print() вместо return.

Другие вопросы по теме