Respons passing yang buruk, kehilangan satu argumen posisi

Baru mengenal python, berasal dari php. Saya ingin mengikis beberapa situs menggunakan Scrapy dan telah melalui tutorial dan skrip sederhana dengan baik. Sekarang menulis real deal muncul kesalahan ini:

Traceback (panggilan terakhir terakhir):

File "C:\Users\Naltroc\Miniconda3\lib\site-packages\twisted\internet\defer.py", baris 653, di _runCallbacks current.result = callback(current.result, *args, **kw)

File "C:\Users\Naltroc\Documents\Python Scripts\tutorial\tutorial\spiders\quotes_spider.py", baris 52, di parse self.dispatchersite

TypeError: tesaurus() tidak ada 1 argumen posisi yang diperlukan: 'respons'

Scrapy secara otomatis membuat instance objek ketika perintah shell scrapy crawl words dipanggil.

Dari apa yang saya pahami, self adalah parameter pertama dari metode kelas apa pun. Saat memanggil metode kelas, Anda tidak meneruskan self sebagai argumen dan malah mengirimkannya ke variabel Anda.

Pertama ini disebut:

# Scrapy automatically provides `response` to `parse()` when coming from `start_requests()`
def parse(self, response):
        site = response.meta['site']
        #same as "site = thesaurus"
        self.dispatcher[site](response)
        #same as "self.dispatcher['thesaurus'](response)

Kemudian

def thesaurus(self, response):
        filename = 'thesaurus.txt'
        words = ''
        ul = response.css('.relevancy-block ul')
        for idx, u in enumerate(ul):
            if idx == 1: 
                break;
            words = u.css('.text::text').extract()

        self.save_words(filename, words)

Di php, ini harus sama dengan memanggil $this->thesaurus($response). parse jelas mengirimkan response sebagai variabel, tetapi python mengatakan itu hilang. Ke mana perginya?

Kode lengkap di sini:

import scrapy

class WordSpider(scrapy.Spider):
    def __init__(self, keyword = 'apprehensive'):
        self.k = keyword
    name = "words"
    # Utilities
    def make_csv(self, words):
        csv = ''
        for word in words:
            csv += word + ','
        return csv

    def save_words(self, words, fp):
        with ofpen(fp, 'w') as f:
            f.seek(0)
            f.truncate()
            csv = self.make_csv(words)
            f.write(csv)

    # site specific parsers
    def thesaurus(self, response):
        filename = 'thesaurus.txt'
        words = ''
        print("in func self is defined as ", self)
        ul = response.css('.relevancy-block ul')
        for idx, u in enumerate(ul):
            if idx == 1:
                break;
            words = u.css('.text::text').extract()
            print("words is ", words)

        self.save_words(filename, words)

    def oxford(self):
        filename = 'oxford.txt'
        words = ''

    def collins(self):
        filename = 'collins.txt'
        words = ''

    # site/function mapping
    dispatcher = {
        'thesaurus': thesaurus,
        'oxford': oxford,
        'collins': collins,
    }

    def parse(self, response):
        site = response.meta['site']
        self.dispatcher[site](response)

    def start_requests(self):
        urls = {
            'thesaurus': 'http://www.thesaurus.com/browse/%s?s=t' % self.k,
            #'collins': 'https://www.collinsdictionary.com/dictionary/english-thesaurus/%s' % self.k,
            #'oxford': 'https://en.oxforddictionaries.com/thesaurus/%s' % self.k,
        }

        for site, url in urls.items():
            print(site, url)
            yield scrapy.Request(url, meta={'site': site}, callback=self.parse)

person Naltroc    schedule 25.05.2017    source sumber


Jawaban (1)


Ada banyak kesalahan kecil di sekitar kode Anda. Saya mengambil kebebasan untuk membersihkannya sedikit untuk mengikuti idiom python/scrapy yang umum :)

import logging
import scrapy


# Utilities
# should probably use csv module here or `scrapy crawl -o` flag instead
def make_csv(words):
    csv = ''
    for word in words:
        csv += word + ','
    return csv


def save_words(words, fp):
    with open(fp, 'w') as f:
        f.seek(0)
        f.truncate()
        csv = make_csv(words)
        f.write(csv)


class WordSpider(scrapy.Spider):
    name = "words"

    def __init__(self, keyword='apprehensive', **kwargs):
        super(WordSpider, self).__init__(**kwargs)
        self.k = keyword

    def start_requests(self):
        urls = {
            'thesaurus': 'http://www.thesaurus.com/browse/%s?s=t' % self.k,
            # 'collins': 'https://www.collinsdictionary.com/dictionary/english-thesaurus/%s' % self.k,
            # 'oxford': 'https://en.oxforddictionaries.com/thesaurus/%s' % self.k,
        }

        for site, url in urls.items():
            yield scrapy.Request(url, meta={'site': site}, callback=self.parse)

    def parse(self, response):
        parser = getattr(self, response.meta['site'])  # retrieve method by name
        logging.info(f'parsing using: {parser}')
        parser(response)

    # site specific parsers
    def thesaurus(self, response):
        filename = 'thesaurus.txt'
        words = []
        print("in func self is defined as ", self)
        ul = response.css('.relevancy-block ul')
        for idx, u in enumerate(ul):
            if idx == 1:
                break
            words = u.css('.text::text').extract()
            print("words is ", words)
        save_words(filename, words)

    def oxford(self):
        filename = 'oxford.txt'
        words = ''

    def collins(self):
        filename = 'collins.txt'
        words = ''
person Granitosaurus    schedule 25.05.2017
comment
terima kasih atas ulasannya. 1. Apakah ada alasan untuk menambahkan **kwargs ke __init__ jika saya tahu itu hanya akan menggunakan keyword sebagai argumen? 2. Sepertinya fungsi parse berfungsi sebagai pengontrol, pertama-tama dapatkan parser yang tepat lalu meneruskan datanya. Ini masuk akal, tetapi apakah ini satu-satunya cara untuk mengirim response data? 3. Mengapa penggunaan getattr(self, response.meta['site']) memungkinkan pemanggilan metode yang sesuai tanpa mengawalinya dengan self.? - person Naltroc; 25.05.2017
comment
Mengenai #1. Karena Anda mewarisi dari Spider, Anda ingin mewariskan kwarg ke kelas ayah, tidak ada hal khusus di sini yang layak untuk diteruskan, tetapi ini adalah pola yang menjadikannya bukti di masa depan. 2. Anda salah memahami cara kerja scrapy, secara default laba-laba memulai rangkaian permintaan untuk setiap url di start_urls dan dengan panggilan balik default parse(), di mana respons adalah objek respons dari salah satu start_url tersebut. 3. Anda salah memahami apa itu diri; self adalah referensi ke objek kelas saat ini, jadi saat menggunakan getattr Anda tidak memerlukannya karena Anda mendapatkan referensi independen untuk Anda. - person Granitosaurus; 25.05.2017