Краткое руководство по Scrapy (1)

Scrapy

Оригинальная ссылка

предисловие

ScrapyЭто фреймворк сканера, реализованный на чистом языке Python. Простота, удобство использования и высокая масштабируемость делают его основным инструментом в сканере Python. В этой статье используется последняя официальная версия.1.6Исходя из этого, ведется дискуссия от простого использования к углубленному принципу.

Заранее скажу, что туториал есть туториал, в конце концов, нет соответствующего официального документа! Если читатель заинтересуется Scrapy после прочтения этой статьи и намерен узнать больше о Scrapy, пожалуйста, выработайте привычку читать официальную документацию в любое время!

Официальная документация Scrapy

содержание

В этой статье в основном описывается следующее содержание

  • Почему выбирают Scrapy?
  • Привет Скрапи! (упражняться)
  • Как работает Скрейпи?

Что касается первого подраздела «Почему выбирают Scrapy», я предлагаю читателям прочитать его, и я проанализирую свое понимание бизнес-сценариев Scrapy.

Что касается оставшихся двух подразделов, мое первоначальное намерение состояло в том, чтобы поместить «Как работает Scrapy» перед «Hello Scrapy», но, учитывая, что не все хотят сразу понимать теоретические вещи, я сначала поставлю практическую небольшую демонстрацию впереди, надеясь пробудить интерес читателей, а интерес может дать нам более глубокое понимание одной вещи. Поэтому я поместил раздел «Как работает Scrapy» в конец, и я также могу следовать принципу Scrapy в следующей главе!

Почему выбирают Scrapy?

Хотя Scrapy был разработан для выполнения подавляющего большинства задач сканера, все же есть некоторые сценарии, в которых он неприменим.

  • Когда Scrapy не предпочтительнее?
  1. Scrapy — не лучший выбор, когда вы сканируете небольшое количество страниц и ориентируетесь на небольшой сайт. Например, для сканирования некоторых списков фильмов, некоторой новостной информации и т. д. Requests + PyQuery очень хорошо справляется с такими задачами.И Requests, и PyQuery лучше, чем два модуля, поставляемые со Scrapy!

  2. Когда нет общих требований к сканеру, Scrapy не является обязательным. На мой взгляд, реальное преимущество Scrapy заключается в том, что он может настраивать соответствующие «действия паука» для разных типов веб-сайтов.Мощный «ItemLoader» может определять ряд действий обработки для ввода и вывода данных. Если у вас нет необходимости постоянно расширять источник информации, Scrapy фактически не сможет проявить свои максимальные возможности!

  3. Scrapy бессилен, когда вам нужно постепенно очищать данные. Scrapy не имеет функции инкрементного сканирования, потому что сложность инкрементов разная.Если на Scrapy просто выполнять незначительные операции, это можно оценить, но если инкрементальные требования высоки, для Scrapy может быть очень проблематично двигаться. !

Примечание. Приведенные выше три случая просто хотят показать, что Scrapy — не лучший выбор, и это не говорит о том, что это не рекомендуется! Я просто надеюсь, что читатели могут понять, что при выборе фреймворка или технологии не следует следовать тренду.Это очень полезно для хорошего развития проекта, тщательно продумать его в начале дизайна.

  • Когда полезен Scrapy?
  1. Scrapy-redis, неофициальный компонент Scrapy, полезен, когда требуется распределенный дизайн. Сам по себе Scrapy не может реализовать распределенный механизм, но использует rmax для разработкиScrapy-redisЕго можно распространять, и я расскажу об этом позже.

  2. Когда есть потребность в масштабируемости, Scrapy — мощный инструмент. Конкретные причины были объяснены выше и не будут объясняться здесь.

Примечание. Все вышеперечисленные ситуации взяты из моего личного обзора использования Scrapy, только для справки!

Hello Scrapy

Демонстрация использует популярные рейтинги фильмов Douban (Victims of Eternal Reptiles) и все его комментарии в качестве экспериментальной цели и описывает основные функции Scrapy одну за другой. Я полагаю, что читатели смогут хорошо использовать Scrapy после практики этой демонстрации. .

Проект gitHub

Необходимо установить:

  • python (в этой статье используется 3.7)
  • scrapy

Среда установки

  • Установить Скраппи

введите в командной строкеpip install scrapy

Создать Scrapy-проект

Введите в командной строкеscrapy startproject douban_demo, результат показан на следующем рисунке

新建项目

Позже вы можете увидеть, что Scrapy также предлагает нам использоватьgenspiderЭта команда создает наш файл краулера.Перед этим давайте посмотрим, что произошло после выполнения команды.

Просмотр каталога файлов. Мы видим следующую информацию

douban_demo
├── douban_demo
│   ├── items.py       # 数据模型文件
│   ├── middlewares.py # 中间件文件,配置所有中间件 
│   ├── pipelines.py   # 管道文件,用于处理数据输出
│   ├── settings.py    # douban_demo 的配置文件
│   └── spiders        # Spider类文件夹,所有的Spider均在此存放
└── scrapy.cfg         # 整个Scrapy的配置文件,由Scrapy自动生成

Получив общее представление о назначении каждого файла, давайте начнем наше путешествие по сканеру.

описать сканер

использоватьscrapy genspider douban douban.comЧтобы создать новый файл искателя, этот новый файл искателя будет помещен вdouban_demo/spidersпод.

PS:genspiderиспользованиеscrapy genspider [options] <name> <domain>

В настоящее времяdouban.pyфайл появится вspidersНиже исходное содержание выглядит следующим образом:

# -*- coding: utf-8 -*-
import scrapy


class DoubanSpider(scrapy.Spider):
    name = 'douban'                       # 爬虫名称
    allowed_domains = ['douban.com']      # 允许爬取的域名列表
    start_urls = ['http://douban.com/']   # 开始爬取的资源链接列表

    def parse(self, response):            # 解析数据方法
        pass

Все ваши классы Spider в проекте Scrapy должны наследоватьscrapy.Spidername,start_urlsа такжеparseМетоды-члены должны быть объявлены в каждом классе Spider. Можно использовать дополнительные свойства Spider и методы-члены.нажмите на эту ссылку

Затем просто поместите ссылку на наш объект сканирования вstart_urlsвнутри мы можем использоватьhttps://movie.douban.com/chartдля экспериментального объекта.

будетDoubanSpiderсерединаstart_urlsЗначение заменяется наstart_urls = ['https://movie.douban.com/chart']

Используйте метод оболочки для тестирования страницы

Scrapy также дает намshellпорядок для насshellТест извлечения данных страницы выполняется в методе, более эффективном, чем метод request+pyquery.

Формат команды:scrapy shell urls

Введите в командной строкеscrapy shellВходитьshellмодель.

Примечание. Не спешите добавлять URL-адреса в это время, потому что наш тестовый объект обнаружил UA, и 403 появится, если вы напрямую введете тестовую ссылку. Нет конкретных ограничений на каталог, в который следует вводить эту команду.

Результат выглядит следующим образом:

(venv) ➜  douban_demo scrapy shell --nolog                                 
[s] Available Scrapy objects:
[s]   scrapy     scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s]   crawler    <scrapy.crawler.Crawler object at 0x106c5c550>
[s]   item       {}
[s]   settings   <scrapy.settings.Settings object at 0x108e18898>
[s] Useful shortcuts:
[s]   fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s]   fetch(req)                  Fetch a scrapy.Request and update local objects 
[s]   shelp()           Shell help (print this help)
[s]   view(response)    View response in a browser

На данный момент мы видим, что мы вошли в интерфейс, похожий на интерактор командной строки Python, Прежде всего, чтобы предотвратить Douban 403, мы должныsettingsдобавить внутрьDEFAULT_REQUEST_HEADERSатрибут, это словарь заголовка запроса, пока Scrapy обнаружит этот параметр, он добавит его значение в заголовок запроса.

Значения следующие:

DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 \
  (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
}

Добавьте заголовки запроса по умолчанию, введя в интерактивном интерфейсе

>>> settings.DEFAULT_REQUEST_HEADERS = {
...   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
...   'Accept-Language': 'en',
...   'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 \
...   (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'
... }

повторно войтиsettings.DEFAULT_REQUEST_HEADERSПроверьте, успешно ли добавлено.

После завершения настройки мы можем использоватьfetch(urls)команда для сканирования страницы, которую нам нужно протестировать

типfetch('https://movie.douban.com/chart')чтобы увидеть содержимое

2019-06-03 23:06:13 [scrapy.core.engine] INFO: Spider opened
2019-06-03 23:06:13 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://movie.douban.com/robots.txt> (referer: None)
2019-06-03 23:06:14 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://movie.douban.com/chart> (referer: None)

Из журнала мы видим, что целевая страница была успешно получена.Перед получением страницы мы также можем знать, что сначала к ней обратился scrapy.robots.txtфайл, это хорошая привычка сканера, и все извлечения страниц с помощью скрапинга будут следоватьrobots.txtвнутри правил, если вы не хотите следовать этому правилу, вы можетеsettingsконфигурацияROBOTSTXT_OBEY = False.

В этот момент вы можете использоватьresponse.textчтобы проверить, получили ли мы исходный код для всей страницы. Все операции парсинга ресурсов в scrapy интегрированы вresponseВ этом объекте болееresponseВведение можетнажмите на эту ссылку

Страница анализа

Страница рейтинга фильмов

Проверка элемента на странице

元素检查

Вы можете видеть, что контент, который нам нужно просканировать, находится вtableв. потому что на странице несколькоtable, поэтому вам нужно только перебрать его.

существуетshellиспользуется вresponse.css('table')получить всеtableэлементы, все из которых используются в этой статьеcss selectorсделать выбор элемента,xpathВы также можете переключиться самостоятельно.

Информация о каждом фильме находится вtableпод этикеткойtr.itemв.

Ссылку на детали фильма можно использоватьa.nbg::attr(href)получить

Фотографии фильмов, которые мы можем использоватьa.nbg > img::attr(src)получить

Обработка названий фильмов немного сложнее.Из приведенного выше рисунка видно, что у фильмов может быть несколько имен, все из которых заключены вdiv.pl2 > aвнизу, где другие имена вdiv.pl2 > a > spanНиже, поэтому нам нужно сделать некоторое форматирование имени, например, убрать пробелы, новые строки и т. д.

Так что название фильма можно использоватьdiv.pl2 > a::textиdiv.pl2 > a > span::textполучается отдельно, но таким образомdiv.pl2подaТегов много, нужно использовать только первыйextract_first()метод удаления первогоSelectorсодержимое элемента и преобразуется вstr.

Синопсис фильма просто нужно использоватьp.pl::textможно получить в

страница обзора фильма

Сращивание после ссылки на соответствующую информацию о фильмеcomments?status=PПерейти на страницу обзора фильма.

影评页面

Можно видеть, что данные обзора фильма состоят из несколькихcomment-itemкомпозиция, содержание обзора фильма завернуто вdiv.commentСледовательно, в соответствии с вышеуказанным методом анализа также может быть найден соответствующий метод сбора данных. здесь не раскрыто

Реализовать идеи

  1. создать дваparseметод:parse_rankиparse_comments,parse_rankОтвечает за обработку страницы списка лидеров фильмов,parse_commentsОтвечает за обработку соответствующей страницы комментариев.

  2. переписатьSpiderКатегорияstart_requestsметод, заполнитьurlа такжеcallbackЗначение атрибута, потому что вам нужно получить подробную информацию через страницу рейтинга фильмов, прежде чем вы сможете получить адрес комментария, который вы хотите, поэтому вstart_requestsвернулся вRequest callbackСвойства должны быть заполнены какself.parse_rank

  3. существуетparse_rankобработка возвращенаreponse, следуйте идеям на «Странице анализа», чтобы анализировать данные и использоватьyieldВыкидывает страницу комментариевRequest,callbackатрибут заполненself.parse_comments

  4. существуетparse_commentsМетод обрабатывает возвращенную страницу комментариев, выдает данные и ссылки на следующую страницу.

Примечание:Spider parseметод: всеparseВсе методы должны возвращать Item (в настоящее время понимается как элемент данных) или Requests (следующий запрос). все здесьparseэто значит конкретноSpiderгенерируется в классеparseметод, но все функции с возможностями синтаксического анализа должны возвращать Item или Requests.

пример кода

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http.request import Request


class DoubanSpider(scrapy.Spider):
    name = 'douban'

    def start_requests(self):
        yield Request(url='https://movie.douban.com/chart', callback=self.parse_rank)

    def parse_rank(self, response):
        for item in response.css('tr.item'):
            detail_url = item.css('a.nbg::attr(href)').extract_first()
            img_url = item.css('a.nbg > img::attr(src)').extract_first()
            main_name = item.css('div.pl2 > a::text').extract_first()
            other_name = item.css('div.pl2 > a > span::text').extract_first()
            brief = item.css('p.pl::text').extract_first()
            main_name = main_name.replace('\n', '').replace(' ', '')

            yield {
                'detail_url': detail_url,
                'img_url': img_url,
                'name': main_name+other_name,
                'brief': brief
            }

            yield Request(url=detail_url+'comments?status=P',
                          callback=self.parse_comments,
                          meta={'movie': main_name})

    def parse_comments(self, response):
        for comments in response.css('.comment-item'):
            username = comments.css('span.comment-info > a::text').extract_first()
            comment = comments.css('span.short::text').extract_first()

            yield {
                'movie': response.meta['movie'],
                'username': username,
                'comment': comment
            }
        nexturl = response.css('a.next::attr(href)').extract_first()
        if nexturl:
            yield Request(url=response.url[:response.url.find('?')]+nexturl,
                          callback=self.parse_comments,
                          meta=response.meta)

Запустить поисковый робот

все готово, можноdouban_demoВведите команду в (самом верхнем) каталогеscrapy crawl doubanВы можете видеть, что есть много данных журнала, а также распечатать много информации о фильме и комментарии.

На данный момент мы завершили предварительное сканирование рейтинга фильмов и комментариев Douban. Конечно, Douban ограничивает количество комментариев, которые могут просматривать пользователи, не вошедшие в систему, и определяет поведение сканера. Мы поговорим об этих механизмах предотвращения сканирования в будущем.

Итак, теперь вопрос в том, как я должен сохранить данные?

Scrapy предоставляет множествоFeed exportsметод, вы можете сохранить выходные данные какjson, json lines, csv, xml

После стартовой команды добавить-o xx.jsonВы можете сохранить файл какjsonФормат.

как:scrapy crawl douban -o result.json

Так как данные содержат китайский контент, scrapy используетjson encoderПо умолчанию все данныеascii, поэтому нам нужно установить кодировку данных наutf-8.

только что вsettings.pyПрисоединяйсяFEED_EXPORT_ENCODING = 'utf-8'Вот и все.

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

В это время будет сгенерировано около 2000 фрагментов данных.

резюме

На данный момент мы завершили предварительное сканирование фильмов и обзоров фильмов Douban. Хотя данные могут быть успешно просканированы, это дает людям ощущение, что «я только что написал код для анализа веб-страницы и ввел команду для запуска сканера, и в результате Scrapy может помочь. Я делаю все, от запросов веб-страницы до вывода данных», нам придется продолжить изучение, когда мы наберемscrapy crawl douban -o result.jsonЧто именно делает Scrapy после этой команды запуска.

Как работает Скрейпи?

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

scrapy_architecture

Согласно этому графическому анализу, когда мы печатаемscrapy crawl douban -o result.jsonПосле этого Scrapy сделал следующее

  1. Crawlerполучилаcrawlбудет активирован после команды, активированнойnameзаdoubanизSpider, при созданииEngine, в это время нашDoubanSpiderактивирован.

  2. когдаDoubanSpiderПосле новостройки,EngineобнаружитSpider, что является нашей очередью запросовstart_urlsатрибут илиstart_requestsметод. Оба они должны быть итерируемыми объектами, поэтому понятно, что в нашем примере кодаstart_requestsметод зачем использоватьyieldбросать. Сгенерировано в это времяRequestобъект, всеRequestобъекты будут проходить первымиSpider MiddlewaresЭто промежуточное ПО, на данном этапе нам нужно понимать промежуточное ПО только как мост, нам не нужно вникать в то, что сейчас находится на мосту.

  3. SpiderпроизведеноRequestобъект будет проходитьEngineОтправить вSchedulerВ планировщике планировщик будетRequestПрисоединяйтесь к очереди запросов, как только это можно будет запланировать,RequestпройдетDownloader Middlewaresэти мосты достигаютDownloader,DownloaderДоступ к указанному Интернет-ресурсу будет осуществляться в соответствии с запрошенным контентом, и этот процесс является асинхронным.

  4. когдаDownloaderзавершить одинRequestПосле выполнения задачи ресурс будет упакован вResponse, который будет содержать исходныйRequestинформация, инкапсулированный парсер и т. д., в примере мы можем видеть вparse_rankброшенный вRequestнесущийmetaданные, послеmetaпродолжай экономитьparse_commentsизresponseвнутри.

  5. В это время всеResponseпройдет сноваDownloader Middlewaresэти мосты, а затемEngineа такжеSpider Middlewaresвернуться к соответствующемуSpider, и активирует соответствующийcallbackфункция и, наконец, выполняет то, что мы написалиparseкод в методе. когдаparseбросить сноваRequestКогда объект будет возвращен, шаги (3-5) будут выполнены повторно.

  6. когдаSpiderПри броске данных (Item) он будет проходить сноваSpider MiddlewaresприбытьItem Pipeline, но мы неItem Pipelineуказать какое-либо действие, чтобы он просто бросалItem, тогда будетloggerЗахватите этот вывод, то есть мы можем видеть, что в консоли есть сгенерированные данные, так как мы использовали-oинструкция, такexporterбудетitemВывод в соответствующем формате, и у нас есть указанныйresult.jsonнабор данных.

Суммировать

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

Если приведенная выше точка зрения неверна, добро пожаловать, Ячжэн!