Обработка нескольких файловых вставок по нескольким запросам - PullRequest
0 голосов
/ 19 июня 2019

Используя Scrapy, я борюсь с тем, как добиться определенного результата.Я пытаюсь очистить финансовые документы от Комиссии по ценным бумагам и биржам.Задача кратко изложена ниже.

  1. Создание URL-адресов запроса компании из Центрального ключа индекса (cik) [каталог] [1]
  2. Следуйте документу компании [страница индекса] [2] иизвлеките ссылки document.
  3. Перейдите к документу [ссылки] [3] и извлеките ссылки 10-K.txt ( Описание: полный текстовый файл для отправки ).
  4. Очистите .txt и сохраните документ в documents.

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

[{cik_number : company_index_1,
  documents : [document_1,
               ...
               document_n]},
 {cik_number : company_index_2,
  documents : [document_1,
               ...
               document_n]}
]

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

[{'cik': ['1011290'],
 'documents': [document_1},
 ...
 {'cik': ['1011290'],
 'documents': [document_n]}
]

Код, использованный для генерации этого вывода, приведен ниже. Только для целей тестирования, я просто добавляю значение response.url к documents, чтобы упростить вывод.

#spider.py

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.loader import ItemLoader
from document_scraper.items import CikItem

class MySpider(scrapy.Spider):
    name = 'demo'
    start_urls = ["https://www.sec.gov/divisions/corpfin/organization/cfia-123.htm"]

    custom_settings = {
        'DOWNLOAD_DELAY' : 0.25,
        'FEED_FORMAT' : 'json',
        'FEED_URI' : 'item.json'
    }

    def parse(self, response):

        for sel in response.xpath('(//*[@id="cos"]//tr)[last()]'):
            loader = ItemLoader(item = CikItem(), response = response)
            loader.add_value('cik', sel.xpath("td[2]//text()").extract_first())

            yield  response.follow(
                'https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK={}&type=10-K' \
            '&dateb=&owner=exclude&count=40'.format(sel.xpath("td[2]//text()").extract_first()),
                callback = self.index,
                meta = {"item" : loader.load_item()}
            )

    def index(self, response):

        document_buttons = response.xpath('//*[@id="documentsbutton"]/@href')

        for _url in document_buttons.extract():
            yield response.follow(
                _url,
                callback=self.parse_page_two,
                meta={"item": response.meta['item']}
            )

    def parse_page_two(self, response):

        filing_txt = response.xpath('(//*[contains(@href, ".txt")])[last()]/@href')

        for _url in filing_txt.extract():
            yield response.follow(
                _url,
                callback=self.parse_page_three,
                meta={"item": response.meta['item']}
            )

    def parse_page_three(self, response):

        next_loader = ItemLoader(item = response.meta['item'], response = response)
        next_loader.add_value('documents', response.url)

        yield next_loader.load_item()

Файл items.py выглядит следующим образом.

from scrapy.item import Item, Field
from scrapy.loader.processors import TakeFirst, Identity

class CikItem(Item):
    cik = Field()
    documents = Field()

Обновление

Мне удалось получить фрагмент кода, который достигает желаемого результата.Файл spider.py выглядит следующим образом.

class MySpider(scrapy.Spider):
    name = 'demo'
    start_urls = ["https://www.sec.gov/divisions/corpfin/organization/cfia-123.htm"]

    custom_settings = {
        'DOWNLOAD_DELAY' : 0.25,
        'FEED_FORMAT' : 'json',
        'FEED_URI' : 'item.json'
    }

    def parse(self, response):

        for sel in response.xpath('(//*[@id="cos"]//tr)[last()]'):

            item = CikItem()
            item['cik'] = sel.xpath("td[2]//text()").extract_first()
            item['documents'] = []

            yield response.follow(
                'https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK={}&type=10-K' \
            '&dateb=&owner=exclude&count=40'.format(sel.xpath("td[2]//text()").extract_first()),
                callback = self.index,
                meta = {'item' : item}
            )

    def index(self, response):

        document_buttons = response.xpath('//*[@id="documentsbutton"]/@href')

        for _url in document_buttons.extract():
            yield response.follow(
                _url,
                callback=self.parse_page_two,
                meta={'item': response.meta['item']}
            )

    def parse_page_two(self, response):

        filing_txt = response.xpath('(//*[contains(@href, ".txt")])[last()]/@href')

        for _url in filing_txt.extract():
            yield response.follow(
                _url,
                callback=self.parse_page_three,
                meta={'item': response.meta['item']}
            )

    def parse_page_three(self, response):

        item = response.meta['item']
        item['documents'].append(response.url)

        if len(self.crawler.engine.slot.inprogress) == 1:
            return item

Мне было бы интересно узнать, как можно улучшить этот код и можно ли реализовать ItemLoader() для выполнения этой задачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...