Я использую универсальных пауков со списком нескольких URL-адресов в поле start_urls
.
Можно ли экспортировать один файл json
для каждого URL-адреса?
Насколько я знаю, можно указать только один путь к одному конкретному выходному файлу.
Любые идеи, как решить эту проблему, приветствуются!
Обновлено: Это мой класс пауков:
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class MySpider(CrawlSpider):
name = 'my_spider'
start_urls = start_urls = ['www.domain1.com','www.domain2.com',
'www.domain3.com']
custom_settings = {
'FEED_EXPORT_ENCODING': 'utf-8',
'DEPTH_LIMIT': '1',
'FEED_URI': 'file:///C:/path/to/result.json',
}
rules = (
Rule(LinkExtractor(allow=r"abc"), callback='parse_item', follow=True),
)
def parse_item(self, response):
all_text = response.xpath("//p/text()").getall()
yield {
"text": " ".join(all_text),
"url": response.url,
}
пример Конвейер, который сохраняет элементы с разными категориями в разных файлах — он использует значение из item
для выбора имени файла: furas/примеры-python/scrapy/сохранение-категорий-в-разделенных-файлах
вы также можете запустить три отдельных сканера с разными доменами и разными файлами.
документация показывает аналогичный конвейер в Экспортеры предметов
Хорошо, кажется, что это определенно возможно. Это хорошо знать. Я думаю о лучшем подходе для моего паука. Если бы я добавил его в свой исходный пост, чтобы было легче говорить о том, какой вариант предпочтительнее.
Я вижу, вы уже получили ответ с кодом - и обе версии кажутся нормальными. Используйте версию, которая вам нравится.
Пожалуйста, взгляните на stackoverflow.com/questions/71679403/…. Я поднял вопрос вдогонку.
Вы можете сохранить элементы в пауке как Учебник по скрейпу, например:
import scrapy
import json
DICT = {
'https://quotes.toscrape.com/page/1/': 'domain1.json',
'https://quotes.toscrape.com/page/2/': 'domain2.json',
}
class MydomainSpider(scrapy.Spider):
name = "mydomain"
start_urls = [
'https://quotes.toscrape.com/page/1/',
'https://quotes.toscrape.com/page/2/',
]
def parse(self, response):
filename = DICT[response.url]
with open(filename, 'w') as fp:
json.dump({"content": response.body.decode("utf-8")}, fp)
Переменная DICT
предназначена только для указания имени файла JSON, но вы также можете использовать домен в качестве имени файла.
Вы можете попробовать использовать process_item
в pipelines.py
следующим образом:
from scrapy.exporters import JsonItemExporter
class SaveJsonPipeline:
def process_item(self, item, spider):
filename = item['filename']
del item['filename']
JsonItemExporter(open(filename, "wb")).export_item(item)
return item
item['filename']
для сохранения имени файла для каждого start_url
. Вам также нужно установить items.py
, например:
import scrapy
class MydomainItem(scrapy.Item):
filename = scrapy.Field()
content = scrapy.Field()
твой паук:
import scrapy
from ..items import MydomainItem
DICT = {
'https://quotes.toscrape.com/page/1/': 'domain1.json',
'https://quotes.toscrape.com/page/2/': 'domain2.json',
}
class MydomainSpider(scrapy.Spider):
name = 'mydomain'
allowed_domains = ['mydomain.com']
start_urls = [
'https://quotes.toscrape.com/page/1/',
'https://quotes.toscrape.com/page/2/',
]
def parse(self, response):
item = MydomainItem()
item["filename"] = DICT[response.url]
item["content"] = response.body.decode("utf-8")
yield item
Перед запуском вам нужно добавить конвейер в настройках.
ITEM_PIPELINES = {
'myproject.pipelines.SaveJsonPipeline': 300,
}
Я новичок в Scrapy, и все мои пауки не используют Scrapy.Item
и Scrapy.Field
. Знаете ли вы, как будет выглядеть ваше решение при использовании yield
без Scrapy.Item
и Scrapy.Field
?
Пожалуйста, взгляните на мое редактирование в моем исходном сообщении. Я добавил еще немного информации.
@Daniel Вы можете использовать обычный словарь item = dict()
вместо item = MydomainItem()
- и он все равно должен работать
@Daniel, ты можешь использовать обычный словарь, как сказал @furas. Вы можете изменить item = MydomainItem()
на item = {}
, и все тоже работает нормально.
Пожалуйста, взгляните на stackoverflow.com/questions/71679403/…. Я поднял уточняющий вопрос.
вам нужно будет создать собственный класс
Pipeline
сprocess_item()
, который сохранитitem
в разных файлах. Возможно, потребуется указать URL-адрес с помощьюitem