Далее представлен простой проект для завершения процесса сканирования Scrapy. Благодаря этому процессу мы можем получить общее представление об основном использовании и принципах Scrapy.
1. Подготовка
Задачи, которые необходимо выполнить в этом разделе, следующие.
-
Создайте проект Scrapy.
-
Создайте паука для обхода сайта и обработки данных.
-
Экспортируйте очищенный контент через командную строку.
-
База данных MongoDB для сохранения извлеченного содержимого.
Во-вторых, подготовка
Нам нужно установить фреймворк Scrapy, библиотеки MongoDB и PyMongo.
Три, создать проект
Создайте проект Scrapy, файловый проект можно использовать напрямую
scrapy
Команда генерируется, и команда выглядит так:
scrapy startproject教程
Эту команду можно запустить в любой папке.Если у вас возникнут проблемы с разрешениями, вы можете добавить sudo для запуска команды.Эта команда создаст папку с именем tutorials.Структура папок следующая. :
scrapy.cfg#Scrapy部署时的配置文件
教程#项目的模块,需要从这里引入
__init__.py
items.py#Items的定义,定义爬取的数据结构
middlewares.py#Middlewares的定义,定义爬取时的中间件
pipelines.py#管道的定义,定义数据管道
settings.py#配置文件
蜘蛛#放置蜘蛛的文件夹
__init__.py
В-четвертых, создайте паука
Spider — это класс, определенный сам по себе, и Scrapy использует его для сканирования контента с веб-страниц и анализа результатов сканирования. Однако этот класс должен наследовать класс паука, предоставленный Scrapy.
scrapy.Spider
, но также определите имя паука и начальный запрос, а также то, как обрабатывать результаты обхода.
Вы также можете использовать командную строку для создания паука, например, чтобы сгенерировать паука для кавычек, вы можете выполнить следующую команду:
光盘教程
scrapy genspider报价
Перейдите в папку учебника, которую вы только что создали, выполните, а затем
genspider
Заказ. Первый параметр — это имя паука, а второй параметр — доменное имя веб-сайта. После завершения выполнения в папке паука есть дополнительный файл quotes.py, который является только что созданным пауком, и его содержимое выглядит следующим образом:
import scrapy
class QuotesSpider (scrapy.Spider):
name = “quotes”
allowed_domains = [ “quotes.toscrape.com” ]
start_urls = [ 'http://quotes.toscrape.com/' ]
def parse (self,response):
通过
Здесь есть три свойства —
name
,
allowed_domains
а также
start_urls
, есть еще способ
parse
.
-
name
, уникальное имя для каждого элемента, используемое для различения разных пауков. -
allowed_domains
, которое является доменным именем, для которого разрешено сканирование. Если первоначальная или последующая ссылка запроса находится не под этим доменным именем, ссылка запроса будет отфильтрована. -
start_urls
, который содержит список URL-адресов, которые паук сканирует при запуске, и который определяет первоначальный запрос. -
parse
, который является методом паука. По умолчанию вызов выполняется, когдаstart_urls
После того, как запрос, сформированный ссылкой в нем, завершит загрузку и выполнение, возвращаемый ответ будет передан этой функции в качестве единственного параметра. Этот метод отвечает за синтаксический анализ возвращаемого ответа, извлечение данных или дальнейшую генерацию запроса для обработки.
Пять, создать проект
Проект — это контейнер для хранения просканированных данных, и его использование похоже на словарь. Однако, по сравнению со словарями, проекты имеют дополнительные механизмы защиты, позволяющие избежать опечаток или неправильного определения полей.
Создание наследования проекта требует
scrapy.Item
класс, определенный и тип
scrapy.Field
поле. Наблюдая за целевым веб-сайтом, мы можем получить содержимое
text
,
author
,
tags
.
Чтобы определить элементы, измените файл items.py следующим образом:
import scrapy
class QuoteItem (scrapy.Item):
text = scrapy.Field()
author = scrapy.Field()
tags = scrapy.Field()
Здесь определены три поля, и мы будем использовать этот элемент при следующем сканировании.
Шесть, разбор ответа
Мы видели над этим,
parse()
параметры метода
resposne
на английском
start_urls
Результат запроса после обхода внутренних ссылок. в таком
parse
метод, мы можем напрямую
response
Переменные для анализа всего игрового контента, например, просмотр исходного кода веб-страницы результата запроса, или дальнейший анализ содержимого исходного кода, или поиск ссылки в результате для получения следующего запроса.
.
Мы видим, что есть как результаты, которые нам нужны, так и ссылка на следующую страницу, с которыми нам нужно иметь дело.
Сначала взгляните на структуру веб-страницы, как показано на следующем рисунке. Каждая страница имеет несколько
class
для
quote
блоков, каждый из которых содержит
text
, ,
author
.
tags
Итак, давайте найдем все
quote
, затем извлеките каждый
quote
содержание в .
. Методом извлечения может быть селектор CSS или селектор XPath.Здесь мы используем селектор CSS для выбора,
parse()
Переписывание метода выглядит так:
高清 解析(个体经营,响应):
报价= response.css( '.quote' )
的报价在报价:
文本= quote.css( ':: .text区段文本').extract_first()
作者= quote.css( ”。 author'text ').extract_first()
tags = quote.css( '.tags .tag :: text').extract()
Здесь мы сначала используем селектор, чтобы выбрать все котировки, которые будут назначены как
quotes
переменная, используя then
for
петля для каждого
quote
обход, каждый разбор
quote
Содержание.
правильно
text
Например, наблюдать за ним
class
для
text
, так что вы можете использовать
.text
селектор для выбора, результатом будет фактически весь узел с меткой
, чтобы получить его содержимое, добавьте
::text
Заходите в электронный журнал. Результатом на данный момент является список длины 1, который все еще необходим, поэтому используйте
extract_first()
подход к элементу электронного журнала. для и
tags
Например, поскольку мы хотим получить все метки, мы используем
extract()
Весь список методов рассылок сделает.
сначала с одним
quote
Например, результаты запроса , каждый метод выбора и результат описываются следующим образом.
.
Исходный код выглядит следующим образом:
< div class = “quote” itemscope = “” itemtype = “http://schema.org/CreativeWork” >
< span class = “text” itemprop = “text” > “我们创造它的世界是一个过程,我们的想法。“ </ span >
< span > by < small class = ”author“ itemprop = ”author“ >阿尔伯特爱因斯坦<
一个 HREF = “/作者/阿尔伯特-爱因斯坦” >(约) </ 一 >
</ 跨度 >
< DIV 类 = “标签” >
标签:
< 元 类 = “关键词” itemprop = “关键词” 内容 = “变化,深的思想,思维,世界” >
< 一 类 = “标签” HREF = “/标签/变更/页/ 1 /” >变更 </ 一 >
<一个 class =“标记” HREF = “/标记/深想法/页面/ 1 /” >深思想 </ 一 >
< 一 类 = “标签” HREF = “/标签/思维/页面/ 1 /” >思 </ 一 >
< 一 类 = “标签” HREF = “/标签/世界/页面/ 1 /” >世界 </ 一 >
</ DIV >
</ DIV >
Результаты возврата различных селекторов следующие.
1. цитата.css('.текст')
[<Selector xpath =“descendant-or-self :: * [@ class and contains(concat('',normalize-space(@class),''),'text')]”data ='<span class = “text”itemprop =“text”>“The'>]
2. цитата.css('.текст::текст')
[<Selector xpath =“descendant-or-self :: * [@ class and contains(concat('',normalize-space(@class),''),'text')] / text()”data =' “我们创造它的世界是一个公关>]
3. цитата.css('.text').extract()
['span class =“text”itemprop =“text”>“我们创造它的世界是我们思考的过程。不改变我们的想法就无法改变。“</ span>']
4. цитата.css('.text::text').extract()
[''我们创造的世界是我们思考的过程。不改变我们的想法就无法改变。“']
5. quote.css('.text::text').extract_first()
“我们创造它的世界是我们思考的过程。如果不改变我们的想法,它就不能改变。“
Таким образом, для
text
, чтобы получить первый элемент результата, используйте так
extract_first()
метод, для
tags
, чтобы получить список всех результатов, используйте так
extract()
метод.
Семь, используйте проект
Элемент определен выше, и следующим шагом будет его использование.Предмет можно понимать как словарь, но он должен быть создан при объявлении. Затем назначьте каждое поле проекта с результатом анализа только сейчас по очереди и, наконец, верните продукт.
QuotesSpider
Переписка выглядит так:
进口 scrapy
从 tutorial.items 导入 QuoteItem
类 QuotesSpider (scrapy.Spider) :
名称= “引号”
allowed_domains = [ “quotes.toscrape.com” ]
start_urls = [ 'http://quotes.toscrape.com/' ]
DEF 解析(个体,响应):
报价= response.css('.quote' )
用于引用在引号:
项= QuoteItem()
项[ '文本' ] = quote.css(':: .text区段文本')。extract_first()
项目['author' ] = quote.css('.author :: text').extract_first()
item [ 'tags' ] = quote.css('.tags .tag :: text').extract()
yield item
Таким образом, все содержимое домашней страницы анализируется и назначается одному за другим.
QuoteItem
.
Восемь, последующие запросы
Описанная выше операция реализует очистку содержимого с начальной страницы. Итак, как просканировать содержимое следующей страницы? Это требует от нас поиска информации на текущей странице для создания следующего запроса, а затем поиска информации на следующей запрошенной странице для построения следующего запроса. Таким образом, это повторяется и повторяется, чтобы реализовать сканирование всего сайта.
Потяните страницу прямо сейчас вниз, как показано на рисунке ниже.
Вот кнопка, чтобы просмотреть его исходный код, вы можете найти, что его ссылка /page/2/, полная ссылка: http://quotes.toscrape.com/page/2, по этой ссылке мы можем построить дальше спрашивай.
Scrapy.Request используется при построении запроса, здесь мы передаем два параметра —
url
а также
callback
, описание этих двух параметров выглядит следующим образом.
-
url
: это ссылка запроса. -
callback
:. Это функция обратного вызова, когда запрос, определяющий функцию обратного вызова, завершен., получите ответ, механизм передаст ответ в качестве параметра функции обратного вызова для анализа или генерации следующего запроса., текст обратного вызова функции, как указано вышеparse()
показано.
из-за
parse()
анализирует
text
,
author
,
tags
метод, а структура следующей страницы такая же, как структура страницы, которая только что была проанализирована
, так что снова мы можем использовать
parse()
способ парсинга страницы.
Следующее, что нам нужно сделать, это использовать селектор, чтобы получить ссылку на следующую страницу и сгенерировать запрос.
,существует
parse()
Добавьте следующий код после метода:
next = response.css('.pager .next a :: attr(href)').extract_first()
url = response.urljoin(next)
yield scrapy.Request(url = url,callback = self.parse)
Первое предложение кода сначала получает ссылку следующей страницы через селектор CSS, то есть получает ссылку в гиперссылке
href
Атрибуты. используется здесь
::attr(href)
работать. а потом позвони
extract_first()
Методы содержания электронного журнала.
Второй код вызывает
urljoin()
метод,
urljoin()
Метод может преобразовать относительный URL-адрес в абсолютный URL-адрес, например, получить адрес следующей страницы /yes/page 2.
urljoin()
Результат, полученный после обработки метода: http://quotes.toscrape.com/pages/2/.
Предложение третьего кода прохода
url
Придаточное предложение:
callback
Переменная создает новый запрос, функция обратного вызова
callback
все еще использую
parse()
метод. После завершения запроса ответ будет передан повторно
parse
Метод обработки, получить результат парсинга второй страницы, а затем сгенерировать следующую страницу второй страницы, то есть запрос третьей страницы. Таким образом, поисковый робот входит в цикл до последней страницы.
С помощью нескольких строк кода мы можем легко реализовать цикл очистки для очистки результатов каждой страницы.
Теперь, после перезаписи всего
Spider
Класс выглядит так:
进口 scrapy
从 tutorial.items 导入 QuoteItem
类 QuotesSpider (scrapy.Spider) :
名称= “引号”
allowed_domains = [ “quotes.toscrape.com” ]
start_urls = [ 'http://quotes.toscrape.com/' ]
DEF 解析(个体,响应):
报价= response.css('.quote' )
用于引用在引号:
项= QuoteItem()
项[ '文本' ] = quote.css(':: .text区段文本')。extract_first()
项目['author' ] = quote.css('.author :: text').extract_first()
item [ 'tags' ] = quote.css('.tags .tag :: text').extract()
yield item
next = response.css('.pager .next a :: attr(“href”)').extract_first()
url = response.urljoin(next)
yield scrapy.Request(url = url,callback = self.parse)
Девять, беги
Затем перейдите в каталог и выполните следующую команду:
scrapy抓取报价
Вы можете увидеть текущий результат Scrapy.
2017-02-19 13:37:20 [scrapy.utils.log]信息:Scrapy 1.3.0开始(bot:教程)
2017-02-19 13:37:20 [scrapy.utils.log]信息:重写设置:{'NEWSPIDER_MODULE':'tutorial.spiders','SPIDER_MODULES':['tutorial.spiders'],'ROBOTSTXT_OBEY':True ,'BOT_NAME':'教程'}
2017-02-19 13:37:20 [scrapy.middleware]信息:启用扩展:
[ 'scrapy.extensions.logstats.LogStats',
'scrapy.extensions.telnet.TelnetConsole',
'scrapy.extensions.corestats.CoreStats']
2017-02-19 13:37:20 [scrapy.middleware]信息:启用下载中间件:
[ 'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
'scrapy.downloadermiddlewares.retry.RetryMiddleware',
'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
'scrapy.downloadermiddlewares.stats.DownloaderStats']
2017-02-19 13:37:20 [scrapy.middleware]信息:启用蜘蛛中间件:
[ 'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
'scrapy.spidermiddlewares.referer.RefererMiddleware',
'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
'scrapy.spidermiddlewares.depth.DepthMiddleware']
2017-02-19 13:37:20 [scrapy.middleware]信息:启用项目管道:
[]
2017-02-19 13:37:20 [scrapy.core.engine]信息:蜘蛛打开
2017-02-19 13:37:20 [scrapy.extensions.logstats]信息:爬行0页(0页/分钟),刮0项(0项/分钟)
2017-02-19 13:37:20 [scrapy.extensions.telnet] DEBUG:Telnet控制台监听127.0.0.1:6023
2017-02-19 13:37:21 [scrapy.core.engine] DEBUG:Crawled(404)<GET http://quotes.toscrape.com/robots.txt>(referer:无)
2017-02-19 13:37:21 [scrapy.core.engine] DEBUG:Crawled(200)<GET http://quotes.toscrape.com/>(referer:无)
2017-02-19 13:37:21 [scrapy.core.scraper]调试:从<200 http://quotes.toscrape.com/刮掉>
{'作者':爱因斯坦爱因斯坦',
'标签':[u'change',u'deep-thoughts',u'thinking',u'world'],
'文本':u'\ u201c我们创造它的世界是我们思考的过程。不改变我们的想法就不能改变。\ u201d'}
2017-02-19 13:37:21 [scrapy.core.scraper]调试:从<200 http://quotes.toscrape.com/刮掉>
{'作者':u'JK罗琳',
'tags':[u'abilities',u'choices'],
'文本':你是我们的选择,哈利,这表明我们真正的存在,远远超过我们的能力。\ u201d'}
...
2017-02-19 13:37:27 [scrapy.core.engine]信息:关闭蜘蛛(完成)
2017-02-19 13:37:27 [scrapy.statscollectors]信息:倾销Scrapy统计信息:
{'downloader / request_bytes':2859,
'downloader / request_count':11,
'downloader / request_method_count / GET':11,
'downloader / response_bytes':24871,
'downloader / response_count':11,
'downloader / response_status_count / 200':10,
'downloader / response_status_count / 404':1,
'dupefilter / filtered':1,
'finish_reason':'完成',
'finish_time':datetime.datetime(2017,2,19,5,37,27,227438),
'item_scraped_count':100,
'log_count / DEBUG':113,
'log_count / INFO':7,
'request_depth_max':10,
'response_received_count':11,
'调度程序/出队':10,
'scheduler / dequeued / memory':10,
'调度程序/入队':10,
'scheduler / enqueued / memory':10,
'start_time':datetime.datetime(2017,2,19,5,37,20,321557)}
2017-02-19 13:37:27 [scrapy.core.engine]信息:蜘蛛关闭(完成)
Здесь представлена только часть результатов работы, некоторые результаты сканирования в середине опущены.
Сначала Scrapy выводит номер текущей версии и название запускаемого проекта. Затем выводятся некоторые переписанные конфигурации в текущем settings.py. Затем выведите текущее применяемое промежуточное программное обеспечение и конвейеры.Промежуточное программное обеспечение включено по умолчанию и может быть изменено в settings.py.Конвейеры по умолчанию пусты, и их также можно настроить в settings.py. Они будут объяснены позже.
Следующим шагом является вывод результатов сканирования каждой страницы.Вы можете видеть, что сканер анализирует и переворачивает страницы одновременно, пока не будет просканирован весь контент, а затем завершает работу.
Наконец, Scrapy выводит статистику всего процесса очистки, такую как количество запрошенных байтов, количество запросов, количество ответов, причина завершения и т. д.
Вся программа Scrapy работает успешно. Мы завершили сканирование содержимого веб-сайта с помощью очень простого кода, что намного проще, чем писать небольшую программу до этого.
Десять, сохранить в файл
После запуска Scrapy мы видим только вывод в консоли. Что делать, если я хочу сохранить результаты?
Для выполнения этой задачи на самом деле не требуется никакого дополнительного кода, а экспорт ленты, предоставляемый Scrapy, может легко выводить очищенные результаты. Например, если мы хотим сохранить приведенный выше результат в виде файла JSON, мы можем выполнить следующую команду:
scrapy抓取引号-o quotes.json
После запуска команды в проекте появляется дополнительный файл quotes.json, который содержит весь только что захваченный контент в формате JSON.
Кроме того, мы также можем вывести строку JSON для каждого элемента.Суффикс вывода — JL, что является аббревиатурой jsonline.Команда выглядит следующим образом:
scrapy抓取引号-o quotes.jl
или
scrapy抓取引号-o引用.jsonlines
Также поддерживаются многие выходные форматы, такие как CSV, XML, pickles, marshals и т. д. Он также поддерживает удаленный вывод, такой как FTP, S3 и т. д. Кроме того, другие выходные данные могут быть реализованы путем настройки ItemExporter.
Например, соответствующие выходные данные следующих команд представляют собой CSV, XML, pickle, формат маршала и удаленный вывод FTP:
scrapy抓取引号-o quotes.csv
scrapy抓取引号-o quotes.xml
scrapy抓取引号-o quotes.pickle
scrapy抓取引号-o引用.marshal
scrapy抓取引号-o ftp:// user:pass@ftp.example.com/path/to/quotes.csv
Среди них имя пользователя, пароль, адрес и путь вывода должны быть правильно настроены для вывода FTP, иначе будет сообщено об ошибке.
С помощью Feed Exports, предоставленного Scrapy, мы можем легко вывести очищенные результаты в файл. Для некоторых небольших проектов этого должно быть достаточно. Но если вам нужен более сложный вывод, например вывод в базу данных и т. д., мы можем использовать для этого Item Pileline.
Одиннадцать, используйте Item Pipeline
Если мы хотим выполнять более сложные операции, такие как сохранение результатов в базе данных MongoDB или фильтрация некоторых полезных элементов, мы можем определить для этого конвейер элементов.
Item Pipeline — это конвейер проекта. Когда элемент сгенерирован, он будет автоматически отправлен в конвейер элементов для обработки.Мы используем конвейер элементов для выполнения следующих операций.
-
Очистите HTML-данные.
-
Подтвердите просканированные данные и проверьте просканированные поля.
-
Проверяйте наличие дубликатов и удаляйте дубликаты.
-
Сохраните результаты сканирования в базе данных.
Чтобы реализовать Item Pipeline просто, просто определите класс и реализуйте
process_item()
метод. После включения Item Pipeline этот метод будет автоматически вызываться Item Pipeline.
process_item()
Метод должен возвращать словарь или объект Item, содержащий данные, или вызывать исключение DropItem.
process_item()
Метод имеет два параметра. Один параметр
item
, элемент, сгенерированный пауком, будет каждый раз передаваться в качестве параметра. Другой параметр
spider
, который является экземпляром паука.
Затем мы реализуем Item Pipeline для фильтрации
text
Элемент, длина которого больше 50, и сохраните результат в MongoDB.
Измените файл Pipelines.py в проекте.Содержимое файла, автоматически сгенерированного командной строкой, можно удалить.
, увеличение
TextPipeline
класс со следующим содержимым:
from scrapy.exceptions import DropItem
class TextPipeline (object):
def __init__ (self):
self.limit = 50
def process_item (self,item,spider):
if item [ 'text' ]:
if len(item [ 'text' ]] )> self.limit:
item [ 'text' ] = item [ 'text' ] [ 0:self.limit] .rstrip()+ '...'
return item
else:
return DropItem('Missing Text'))
Этот код определяет предельную длину в конструкторе как
50, чтобы достичь
process_item()
метод, параметр его английский
item
Придаточное предложение:
spide
- R Сначала судит метод.
item
из
text
Существует ли свойство, если нет, бросить
DropItem
Исключение; если оно существует, оцените, больше ли длина 50, если больше, то усеките и соедините многоточие, а затем
item
Вы можете просмотреть отчет.
Далее обрабатываем
item
Сохраняем в MongoDB и определяем другой пайплайн.Также в пайплайнах.py мы реализуем еще один класс.
MongoPipeline
, содержание следующее:
导入 pymongo
类 MongoPipeline (object):
def __init__ (self,mongo_uri,mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler (cls,crawler):
return cls(
mongo_uri = crawler.settings.get(' MONGO_URI'),
mongo_db = crawler.settings.get('MONGO_DB')
)
def open_spider (self,spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client [self.mongo_db]
def process_item (self,item,spider):
name = item .__ class __.__ name__
self.db [name] .insert(dict(item))
return item
def close_spider (self,蜘蛛):
self.client.close()
MongoPipeline
Класс реализует несколько других методов, определенных API.
-
from_crawler
. Это метод класса, с@classmethod
Identity — это способ внедрения зависимостей. Его параметрыcrawler
,пройти черезcrawler
Мы можем получить каждую информацию о конфигурации глобальной конфигурации. В глобальной конфигурации settings.py мы можем определитьMONGO_URI
Придаточное предложение:MONGO_DB
Чтобы указать адрес и имя базы данных, необходимые для подключения к MongoDB, и получить информацию о конфигурации, верните объект класса. Таким образом, определение этого метода в основном используется для получения конфигурации в settings.py.. -
open_spider
. Этот метод вызывается при запуске паука. Некоторые операции инициализации в основном выполняются в вышеуказанной программе. -
close_spider
. Этот метод вызывается, когда паук закрыт. Соединение с базой данных закрыто в вышеуказанной программе.
самое важное
process_item()
метод выполняет операцию вставки данных.
хорошее определение
TextPipeline
Придаточное предложение:
MongoPipeline
После этих двух классов нам нужно использовать их в settings.py.Информация о соединении с MongoDB также должна быть определена.
Добавляем в settings.py следующее:
ITEM_PIPELINES = {
'tutorial.pipelines.TextPipeline':300,
'tutorial.pipelines.MongoPipeline':400,
}
MONGO_URI = 'localhost'MONGO_DB
= 'tutorial'
назначать
ITEM_PIPELINES
Поиск по словарю, имя ключа — это имя класса конвейера, а значение ключа — это приоритет вызова, который представляет собой число Чем меньше число, тем раньше вызывается соответствующий конвейер.
Затем повторите сканирование, команда выглядит следующим образом:
scrapy抓取报价
После завершения сканирования в MongoDB создается учебная база данных, таблица QuoteItem, как показано на следующем рисунке.
длина
text
был обработан и дополнен многоточием, кратким
text
постоянный,
author
Придаточное предложение:
tags
также. соответственно сохраняются.
Двенадцать, исходный код
Кодовый адрес этого раздела: https://github.com/Python3WebSpider/ScrapyTutorial.
Этот ресурс был впервые опубликован в личном блоге Цуй Цинцай Цзин Ми:Практическое руководство по разработке веб-краулера на Python3 | Цзин Ми
Если вы хотите узнать больше информации о поисковых роботах, обратите внимание на мой личный публичный аккаунт WeChat: Coder of Attack.
WeChat.QQ.com/Day/5 Это радость VE Z…(автоматическое распознавание QR-кода)