#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
, на который вы ответили 😀