使用 I/O 绑定应用程序导入静态或动态是否更好
Is it better to import static or dynamic with I/O Bound application
我一直在开发一个 I/O 绑定应用程序,它是一个新闻网络爬虫。我有一个文件,我可以在其中启动我们可以称之为“monitoring.py”的脚本,然后通过选择我想要监控的新闻公司,我添加了一个参数,例如monitoring.py --company=sydsvenskan
然后会触发 sydsvenskan 网络爬虫。
它的作用基本上是这样的:
scraper.py
from __future__ import annotations
from abc import abstractmethod
from typing import ClassVar, Dict
import requests
from lib.vendors.sydsvenskan import sydsvenskan
from lib.vendors.bbc import bbc
class Scraper:
scrapers: ClassVar[Dict[str, Scraper]] = {}
domain: ClassVar[str]
def __init_subclass__(cls) -> None:
Scraper.scrapers[cls.domain] = cls
@classmethod
def for_url(cls, domain, url) -> Scraper:
return cls.scrapers[domain](url)
@abstractmethod
def scrape_feed(self):
pass
@abstractmethod
def scrape_product(self):
pass
class SydsvenskanScraper(Scraper):
domain = 'sydsvenskan'
def __init__(self, url):
self.url = url
def scrape_feed(self):
with requests.get(self.url) as rep:
# FIXME Better way than this atleast :P
if rep:
return sydsvenskan().scrape_feed(rep=rep)
def scrape_product(self):
with requests.get(self.url) as rep:
# FIXME Better way than this atleast :P
if rep:
return sydsvenskan().scrape_product(rep=rep)
class BBCScraper(Scraper):
domain = 'bbc'
def __init__(self, url):
self.url = url
def scrape_feed(self):
with requests.get(self.url) as rep:
# FIXME Better way than this atleast :P
if rep:
return bbc().scrape_feed(rep=rep)
def scrape_product(self):
with requests.get(self.url) as rep:
# FIXME Better way than this atleast :P
if rep:
return bbc().scrape_product(rep=rep)
sydsvenskan.py
from __future__ import annotations
from selectolax.parser import HTMLParser
@attr.dataclass
class Info:
"""Scraped info about product"""
all_articles: set = attr.ib(factory=set)
store: str = attr.ib(factory=str)
name: Optional[str] = attr.ib(factory=str)
image: Optional[str] = attr.ib(factory=str)
class sydsvenskan():
def scrape_feed(self, rep):
doc = HTMLParser(rep.text)
all_products = {
f"https://www.sydsvenskan.se{product_link.attrs['href']}" for product_link in
doc.css('td.search-articles > a, div.product-image > a')
}
return Info(
store="sydsvenskan",
all_products=all_products
)
def scrape_article(self, rep):
doc = HTMLParser(rep.text)
name = "Test"
price = "Test"
image = "Test"
return Info(
store="Sydsvenskan",
name=name,
price=price,
image=image,
)
但是我的问题是,我不知道添加我将来要监控的所有商店的静态导入(最多可以是 40 家新闻公司)是否更好,还是使用动态导入更好只导入我们从参数调用的那个。 (如果我使用动态导入,我确实相信这个问题,当我们使用来自 class Info
的数据类时,我无法从 pycharm 获得帮助,例如 xxxx.price
、xxxx.name
等)
所以我的问题是,什么对我来说更好。要将所有商店作为静态导入还是为我的案例使用动态?
性能问题的通用答案是:衡量然后决定。
你问了两个问题。
使用动态导入会更快吗?
我会这么认为,但以一种非常微不足道的方式。除非计算机 运行 此代码非常受限,否则差异几乎不会被注意到(启动时大约 <1 秒,以及几十兆字节的 RAM)。
您可以通过复制 sydsvenskan.py
文件 40 次来快速测试它,将它们分别导入 scraper.py
和 运行 time python scraper.py
之前和之后。
而且总的来说,喜欢做简单的事情。静态导入比动态导入简单。
即使导入是动态的,PyCharm 仍然可以提供代码见解吗?
简单地说:是的。我测试把它放在一个函数中,它工作正常:
# file: bbc_scraper.py
class BBCScraper:
def scrape(self) -> str:
return "bar"
# file: main.py
def run_scraper_for_bbc():
import bbc_scraper
scraper = bbc_scraper.BBCScraper()
print(scraper.scrape())
我一直在开发一个 I/O 绑定应用程序,它是一个新闻网络爬虫。我有一个文件,我可以在其中启动我们可以称之为“monitoring.py”的脚本,然后通过选择我想要监控的新闻公司,我添加了一个参数,例如monitoring.py --company=sydsvenskan
然后会触发 sydsvenskan 网络爬虫。
它的作用基本上是这样的:
scraper.py
from __future__ import annotations
from abc import abstractmethod
from typing import ClassVar, Dict
import requests
from lib.vendors.sydsvenskan import sydsvenskan
from lib.vendors.bbc import bbc
class Scraper:
scrapers: ClassVar[Dict[str, Scraper]] = {}
domain: ClassVar[str]
def __init_subclass__(cls) -> None:
Scraper.scrapers[cls.domain] = cls
@classmethod
def for_url(cls, domain, url) -> Scraper:
return cls.scrapers[domain](url)
@abstractmethod
def scrape_feed(self):
pass
@abstractmethod
def scrape_product(self):
pass
class SydsvenskanScraper(Scraper):
domain = 'sydsvenskan'
def __init__(self, url):
self.url = url
def scrape_feed(self):
with requests.get(self.url) as rep:
# FIXME Better way than this atleast :P
if rep:
return sydsvenskan().scrape_feed(rep=rep)
def scrape_product(self):
with requests.get(self.url) as rep:
# FIXME Better way than this atleast :P
if rep:
return sydsvenskan().scrape_product(rep=rep)
class BBCScraper(Scraper):
domain = 'bbc'
def __init__(self, url):
self.url = url
def scrape_feed(self):
with requests.get(self.url) as rep:
# FIXME Better way than this atleast :P
if rep:
return bbc().scrape_feed(rep=rep)
def scrape_product(self):
with requests.get(self.url) as rep:
# FIXME Better way than this atleast :P
if rep:
return bbc().scrape_product(rep=rep)
sydsvenskan.py
from __future__ import annotations
from selectolax.parser import HTMLParser
@attr.dataclass
class Info:
"""Scraped info about product"""
all_articles: set = attr.ib(factory=set)
store: str = attr.ib(factory=str)
name: Optional[str] = attr.ib(factory=str)
image: Optional[str] = attr.ib(factory=str)
class sydsvenskan():
def scrape_feed(self, rep):
doc = HTMLParser(rep.text)
all_products = {
f"https://www.sydsvenskan.se{product_link.attrs['href']}" for product_link in
doc.css('td.search-articles > a, div.product-image > a')
}
return Info(
store="sydsvenskan",
all_products=all_products
)
def scrape_article(self, rep):
doc = HTMLParser(rep.text)
name = "Test"
price = "Test"
image = "Test"
return Info(
store="Sydsvenskan",
name=name,
price=price,
image=image,
)
但是我的问题是,我不知道添加我将来要监控的所有商店的静态导入(最多可以是 40 家新闻公司)是否更好,还是使用动态导入更好只导入我们从参数调用的那个。 (如果我使用动态导入,我确实相信这个问题,当我们使用来自 class Info
的数据类时,我无法从 pycharm 获得帮助,例如 xxxx.price
、xxxx.name
等)
所以我的问题是,什么对我来说更好。要将所有商店作为静态导入还是为我的案例使用动态?
性能问题的通用答案是:衡量然后决定。
你问了两个问题。
使用动态导入会更快吗?
我会这么认为,但以一种非常微不足道的方式。除非计算机 运行 此代码非常受限,否则差异几乎不会被注意到(启动时大约 <1 秒,以及几十兆字节的 RAM)。
您可以通过复制 sydsvenskan.py
文件 40 次来快速测试它,将它们分别导入 scraper.py
和 运行 time python scraper.py
之前和之后。
而且总的来说,喜欢做简单的事情。静态导入比动态导入简单。
即使导入是动态的,PyCharm 仍然可以提供代码见解吗?
简单地说:是的。我测试把它放在一个函数中,它工作正常:
# file: bbc_scraper.py
class BBCScraper:
def scrape(self) -> str:
return "bar"
# file: main.py
def run_scraper_for_bbc():
import bbc_scraper
scraper = bbc_scraper.BBCScraper()
print(scraper.scrape())