Python 功能的模式和设计彼此相差很大,但处理方式相似

Python 功能的模式和设计彼此相差很大,但处理方式相似,python,oop,design-patterns,web-scraping,Python,Oop,Design Patterns,Web Scraping,我正在编写一些Python代码来抓取网站,最终我将得到越来越多的定制抓取器,每一个都有大约50行长,并根据需要从特定网站中提取特定信息 我的程序的第一次迭代是一个巨大的文件,它以一个网站为参数,如果它能识别该网站并有自定义代码(使用一个巨大的case语句来检查它是否能识别该网站),它就会删除该网站 显然,这不是一个很好的设计,所以我想做的是将定制的scrape函数拉入它们自己的文件/类中,并使用一个小脚本来命名它们。例如: scrape.py --site google 我希望文件结构类似于:

我正在编写一些Python代码来抓取网站,最终我将得到越来越多的定制抓取器,每一个都有大约50行长,并根据需要从特定网站中提取特定信息

我的程序的第一次迭代是一个巨大的文件,它以一个网站为参数,如果它能识别该网站并有自定义代码(使用一个巨大的case语句来检查它是否能识别该网站),它就会删除该网站

显然,这不是一个很好的设计,所以我想做的是将定制的scrape函数拉入它们自己的文件/类中,并使用一个小脚本来命名它们。例如:

scrape.py --site google
我希望文件结构类似于:

scrape.py
sites/
    google.py
    yahoo.py
    ...
    bing.py
我还没有掌握面向对象,但我认识到这需要它,我正在寻找的可能是一种常见的面向对象模式

正确重构代码有什么帮助吗

PS-我看过Scrapy,但由于各种原因,它并不是我真正需要的。

PPS-我实际上不是在刮搜索网站,我是在刮美国法院网站。

你的重构技术就是我要做的。下面是我如何看待实现这个问题的

首先

我将在站点目录中的所有文件中创建一个名为ScrapeHandler的函数-google.py、yahoo.py等

def ScrapeHandler(...):
    ...

我将在sites目录中创建一个_uinit__uuu.py,其中包含以下内容

scrapers = ["google", "yahoo", ...]
第三

在主文件scrape.py中,我将在运行时加载scraper,以选择适当的刮取逻辑

from sites import scrapers
all_scrapers = {}
......
# Load all scrapers
for scraper_name in scrapers:
    all_scrapers[scraper_name] = __import__('%s.%s' % (sites.__name__, scraper_name), fromlist=[scraper_name], level=0)
# get the input on what to scrape via command line etc
scraper_name = ..
assert scraper_name not in scrapers
# call the function based on name 
scrapeHandler = all_scrapers.get(scraper_name, None)
if scrapeHandler is not None:
    scrapeHandler(....) 

您可以使用
\uuuu init\uuuu
方法将代码放入一个类中以配置所有内容,使用
\u download
方法连接到站点并下载,使用
\u store
方法保存结果,使用
run
方法将所有内容绑定在一起,如下所示:

class Scraper(object):
    def __init__(self, parser, page_generator):
        self._parser = parser
        self._pages = pages

    def _download(self, page):
        # do whatever you're already doing to download it
        return html

    def _store(self, data):
        # Do whatever you're already doing to store the data

    def run(self):
        for page in pages:
            html = self._download(page)
            data = self._parser.parse(html)
            self._store(data)
此类可以存在于
parser.py
文件中

在每个站点特定的文件中,放置两个内容

class Parser(object):
    def parse(html):
        # All of your rules go here

def pages(some, args, if_, you, need, them): # but they should be the same for all files
    return a_list_of_pages_or_generator
然后,您可以使用以下函数设置
python.py
文件:

def get_scraper(name):
    mod = __import__(name)

    parser = mod.Parser()
    pages = mod.pages() # Pass whatever args you need to figure out the urls

    return Scraper(parser, pages)
然后你可以像这样使用它

scraper = get_scraper('google')
scraper.run()
这样做的好处是不需要对
Scraper
类进行任何更改。如果需要使用不同的技巧让服务器与scraper通信,那么可以在每个模块中创建一个
下载程序
类,并像使用
解析器
类一样使用它。如果有两个或多个解析器执行相同的操作,只需将它们定义为单独模块中的通用解析器,并将其导入每个需要它的站点的模块中即可。或者将其子类化以进行调整。如果不知道您是如何下载和解析这些站点的,就很难更加具体


我的感觉是,你可能需要问几个问题才能解决所有的细节,但这将是一次很好的学习体验。

最终,我在这里使用了这两个答案来建立图书馆,但从这一个中借用了更多。非常有用的东西,谢谢!对于处理程序,我最终在我创建的模块中迭代了all变量,但是是的,这里的东西不错。非常感谢。