การตอบกลับแบบ Scrapy ขาดอาร์กิวเมนต์ตำแหน่งหนึ่งรายการ

ใหม่ถึง python มาจาก php.ini ฉันต้องการขูดบางไซต์โดยใช้ Scrapy และได้ผ่านบทช่วยสอนและสคริปต์ง่ายๆ เป็นอย่างดี ตอนนี้การเขียนเรื่องจริงเกิดข้อผิดพลาดนี้:

Traceback (การโทรล่าสุดครั้งล่าสุด):

ไฟล์ "C:\Users\Naltroc\Miniconda3\lib\site-packages\twisted\internet\defer.py", บรรทัด 653 ใน _runCallbacks current.result = callback(current.result, *args, **kw)

ไฟล์ "C:\Users\Naltroc\Documents\Python Scripts\tutorial\tutorial\spiders\quotes_spider.py", บรรทัด 52, ใน parse self.dispatchersite

TypeError: thesaurus() ขาดอาร์กิวเมนต์ตำแหน่งที่จำเป็น 1 รายการ: 'response'

Scrapy จะสร้างอินสแตนซ์ของวัตถุโดยอัตโนมัติเมื่อมีการเรียกใช้คำสั่งเชลล์ scrapy crawl words

จากสิ่งที่ฉันเข้าใจ self เป็นพารามิเตอร์แรกของวิธีการเรียนใด ๆ เมื่อเรียกเมธอดคลาส คุณไม่ต้องส่ง self เป็นอาร์กิวเมนต์ แต่จะส่งตัวแปรของคุณไปแทน

อันดับแรกเรียกว่า:

# 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)

แล้ว

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)

ใน php นี่ควรเหมือนกับการโทร $this->thesaurus($response) เห็นได้ชัดว่า parse กำลังส่ง response เป็นตัวแปร แต่ python บอกว่ามันหายไป มันไปไหน

รหัสเต็มที่นี่:

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 แหล่งที่มา


คำตอบ (1)


มีข้อผิดพลาดเล็กๆ น้อยๆ มากมายรอบๆ รหัสของคุณ ฉันใช้เสรีภาพในการทำความสะอาดเล็กน้อยเพื่อทำตามสำนวน python/scrapy ทั่วไป :)

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
ขอบคุณสำหรับรีวิว 1. มีเหตุผลที่ต้องเพิ่ม **kwargs ลงใน __init__ หรือไม่ ถ้าฉันรู้ว่าจะใช้เพียง keyword เป็นอาร์กิวเมนต์เสมอ 2. ดูเหมือนว่าฟังก์ชัน parse จะทำหน้าที่เป็นตัวควบคุม ขั้นแรกให้รับ parser ที่เหมาะสมก่อน จากนั้นจึงส่งข้อมูลไปให้ นี่สมเหตุสมผล แต่เป็นวิธีเดียวที่จะส่งข้อมูล response ไปรอบ ๆ หรือไม่ 3. เหตุใดการใช้ getattr(self, response.meta['site']) จึงอนุญาตให้เรียกใช้วิธีการที่เหมาะสมโดยไม่ต้องเติม self. นำหน้า - person Naltroc; 25.05.2017
comment
เกี่ยวกับ #1. เนื่องจากคุณได้รับมรดกจาก Spider และต้องการส่งต่อ kwargs ไปยังคลาสพ่อ จึงไม่มีอะไรพิเศษที่นี่ที่คุ้มค่าที่จะส่งต่อ แต่มันคือรูปแบบที่จะพิสูจน์อนาคตนี้ 2. คุณเข้าใจผิดว่า Scrapy ทำงานอย่างไร โดยค่าเริ่มต้น Spider จะเริ่มการร้องขอต่อเนื่องสำหรับทุก url ใน start_urls และด้วยการโทรกลับเริ่มต้น parse() โดยที่การตอบสนองคือออบเจ็กต์การตอบสนองของหนึ่งใน start_url เหล่านั้น 3. คุณเข้าใจผิดว่าตัวตนคืออะไร self เป็นการอ้างอิงถึงคลาสอ็อบเจ็กต์ปัจจุบัน ดังนั้นเมื่อใช้ getattr คุณไม่จำเป็นต้องใช้มันเนื่องจากคุณจะได้รับการอ้างอิงอิสระสำหรับคุณ - person Granitosaurus; 25.05.2017