Как вызвать правильный класс из домена URL

#python #python-3.x #class-variables

Вопрос:

В настоящее время я работаю над созданием веб-обходчика, в котором я хочу вызвать правильный класс, который удаляет веб-элементы с заданного URL-адреса.

В настоящее время я создал:

 import sys
import tldextract
import requests


class Scraper:
    scrapers = {}

    def __init_subclass__(scraper_class):
        Scraper.scrapers[scraper_class.url] = scraper_class

    @classmethod
    def for_url(cls, url):
        k = tldextract.extract(url)
        # return Scraper.scrapers[k.domain]()
        # or
        return cls.scrapers[k.domain]()


class BBCScraper(Scraper):
    url = 'bbc.co.uk'

    def scrape(s):
        print(s)
        # FIXME Scrape the correct values for BBC
        return "Scraped BBC News"


url = 'https://www.bbc.co.uk/'
scraper = Scraper.for_url(url)
scraper.scrape(requests.get(url))
 

Что я пытаюсь сделать прямо сейчас, так это то, что если BBC-это доменное имя, то оно должно войти в class BBCScraper(Scraper): и, поскольку мы называем scraper.scrape(requests.get(url)) его, оно должно затем очистить веб-элементы внутри BBCScraper -> scrape -> Return web elements

Однако у меня есть проблемы, когда я пытаюсь запустить этот скрипт, он выводит:

 Outprint >>> return cls.scrapers[k.domain]() KeyError: 'bbc'
 

Интересно, как я могу вызвать правильный класс в зависимости от домена, который был присвоен методу for_url class

Ответ №1:

Проблема в том, что k.domain возвращается bbc , и вы написали url = 'bbc.co.uk' так одно из этих решений

  • используйте url = 'bbc.co.uk' вместе с k.registered_domain
  • используйте url = 'bbc' вместе с k.domain

И добавьте параметр в scrape метод, чтобы получить ответ

 from abc import abstractmethod
import requests
import tldextract

class Scraper:
    scrapers = {}

    def __init_subclass__(scraper_class):
        Scraper.scrapers[scraper_class.url] = scraper_class
    @classmethod
    def for_url(cls, url):
        k = tldextract.extract(url)
        return cls.scrapers[k.registered_domain]()
    @abstractmethod
    def scrape(self, content: requests.Response):
        pass

class BBCScraper(Scraper):
    url = 'bbc.co.uk'

    def scrape(self, content: requests.Response):
        return "Scraped BBC News"

if __name__ == "__main__":
    url = 'https://www.bbc.co.uk/'
    scraper = Scraper.for_url(url)
    r = scraper.scrape(requests.get(url))
    print(r)  # Scraped BBC News
 

Улучшить

Я бы предложил сохранить атрибут url в , чтобы поместить requests.get его в scrape , чтобы в основном было меньше кода

 class Scraper:
    scrapers = {}

    def __init_subclass__(scraper_class):
        Scraper.scrapers[scraper_class.domain] = scraper_class

    @classmethod
    def for_url(cls, url):
        k = tldextract.extract(url)
        return cls.scrapers[k.registered_domain](url)

    @abstractmethod
    def scrape(self):
        pass


class BBCScraper(Scraper):
    domain = 'bbc.co.uk'

    def __init__(self, url):
        self.url = url

    def scrape(self):
        rep = requests.Response = requests.get(self.url)
        content = rep.text  # ALL HTML CONTENT
        return "Scraped BBC News"   content[:20]


if __name__ == "__main__":
    url = 'https://www.bbc.co.uk/'
    scraper = Scraper.for_url(url)
    r = scraper.scrape()
    print(r)  # Scraped BBC News<!DOCTYPE html><html
 

Комментарии:

1. Привет, Азро! Похоже, это работает, но я получаю предупреждение о Scraper.scrapers[scraper_class.domain] = scraper_class том, где оно написано Unresolved attribute reference 'domain' for class 'Scraper' — Должно ли оно так говорить?

2. @ProtractorNewbie на кого ты переоделся domain = 'bbc.co.uk' ?

3. Я этого не сделал, все, что я сделал, это скопировал и вставил второй код Improve , на который вы ответили 😀