Python Scrapy cara menyimpan data dalam file yang berbeda
Saya ingin menyimpan setiap kutipan dari http://quotes.toscrape.com/disimpan ke dalam file csv (2 field: author, quote). Satu keharusan lainnya adalah menyimpan kutipan ini di file berbeda yang dipisahkan oleh halaman tempat mereka berada. yaitu: (halaman1.csv, halaman2.csv ...). Saya telah mencoba mencapai ini dengan mendeklarasikan ekspor pakan dalam custom_settingsatribut di laba-laba saya seperti yang ditunjukkan di bawah ini. Ini, bagaimanapun, bahkan tidak menghasilkan file bernama page-1.csv. Saya benar-benar pemula yang menggunakan scrapy, coba jelaskan dengan asumsi saya tahu sedikit atau tidak sama sekali.
import scrapy
import urllib
class spidey(scrapy.Spider):
name = "idk"
start_urls = [
"http://quotes.toscrape.com/"
]
custom_settings = {
'FEEDS' : {
'file://page-1.csv' : { #edit: uri needs to be absolute path
'format' : 'csv',
'store_empty' : True
}
},
'FEED_EXPORT_ENCODING' : 'utf-8',
'FEED_EXPORT_FIELDS' : ['author', 'quote']
}
def parse(self, response):
for qts in response.xpath("//*[@class=\"quote\"]"):
author = qts.xpath("./span[2]/small/text()").get()
quote = qts.xpath("./*[@class=\"text\"]/text()").get()
yield {
'author' : author,
'quote' : quote
}
next_pg = response.xpath('//li[@class="next"]/a/@href').get()
if next_pg is not None:
next_pg = urllib.parse.urljoin(self.start_urls[0], next_pg)
yield scrapy.Request(next_pg, self.parse)
Bagaimana saya menjalankan crawler: scrapy crawl idkSebagai pertanyaan tambahan, saya ingin file saya ditimpa dan bukannya ditambahkan seperti saat menentukan -oflag. Apakah mungkin melakukannya tanpa harus memeriksa / menghapus file yang sudah ada sebelumnya dari spider secara manual?
Jawaban
Menyimpan item Anda ke dalam file yang dinamai sesuai halaman tempat Anda menemukannya (afaik) tidak didukung di pengaturan. Jika Anda ingin mencapai ini, Anda dapat membuat fungsionalitas Anda sendiri untuk itu dengan openfungsi python dan csv.writerdalam parsemetode Anda . Opsi alternatifnya adalah menulis pipeline item yang mengelola eksportir item berbeda untuk file berbeda.
Apa yang dapat Anda lakukan dengan pengaturan adalah membatasi jumlah item dalam file dengan FEED_EXPORT_BATCH_ITEM_COUNTpengaturan, yang didukung sejak Scrapy versi 2.3.
Menimpa alih-alih menambahkan ke file juga dapat dilakukan sejak Scrapy 2.4. Di FEEDSAnda dapat mengatur overwriteke True seperti yang ditunjukkan segera.
Jika Anda mengganti Anda custom_settingsdengan yang berikut ini, itu akan menghasilkan file dengan 10 item masing-masing dinamai page-diikuti oleh batch_id, yang dimulai dengan satu. Jadi 3 file pertama Anda akan diberi nama page-1.csv, page-2.csv dan page-3.csv.
custom_settings = {
'FEED_EXPORT_BATCH_ITEM_COUNT': 10,
'FEEDS' : {
'page-%(batch_id)d.csv' : {
'format' : 'csv',
'store_empty' : True,
'overwrite': True
}
}
}
Menerapkan sebagai pipeline
Jika Anda ingin mengimplementasikan ini menggunakan item pipeline, Anda dapat menyimpan nomor halaman di kamus yang Anda kembalikan, yang kemudian diproses dan dihapus oleh item pipeline.
Pipeline di Anda pipelines.py(berdasarkan contoh ini ) akan terlihat seperti ini:
from scrapy.exporters import CsvItemExporter
class PerFilenameExportPipeline:
"""Distribute items across multiple CSV files according to their 'page' field"""
def open_spider(self, spider):
self.filename_to_exporter = {}
def close_spider(self, spider):
for exporter in self.filename_to_exporter.values():
exporter.finish_exporting()
def _exporter_for_item(self, item):
filename = 'page-' + str(item['page_no'])
del item['page_no']
if filename not in self.filename_to_exporter:
f = open(f'{filename}.csv', 'wb')
exporter = CsvItemExporter(f)
exporter.start_exporting()
self.filename_to_exporter[filename] = exporter
return self.filename_to_exporter[filename]
def process_item(self, item, spider):
exporter = self._exporter_for_item(item)
exporter.export_item(item)
return item
Untuk laba-laba Anda, Anda kemudian perlu menambahkan rutinitas untuk mendapatkan halaman tempat Anda berada serta mengatur pipa di Anda custom_settings, yang dapat Anda lakukan seperti berikut:
import scrapy
from ..pipelines import PerFilenameExportPipeline
class spidey(scrapy.Spider):
name = "idk"
custom_settings = {
'ITEM_PIPELINES': {
PerFilenameExportPipeline: 100
}
}
def start_requests(self):
yield scrapy.Request("http://quotes.toscrape.com/", cb_kwargs={'page_no': 1})
def parse(self, response, page_no):
for qts in response.xpath("//*[@class=\"quote\"]"):
yield {
'page_no': page_no,
'author' : qts.xpath("./span[2]/small/text()").get(),
'quote' : qts.xpath("./*[@class=\"text\"]/text()").get()
}
next_pg = response.xpath('//li[@class="next"]/a/@href').get()
if next_pg is not None:
yield response.follow(next_pg, cb_kwargs={'page_no': page_no + 1})
Namun, ada satu masalah dengan ini. File terakhir (halaman-10.csv) tetap kosong karena alasan di luar pemahaman saya. Saya telah bertanya mengapa itu bisa ada di sini .