代码之家  ›  专栏  ›  技术社区  ›  mlissner

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

  •  2
  • mlissner  · 技术社区  · 13 年前

    我正在编写一些Python代码来清理网站,最后我要做的是收集越来越多的自定义清理程序,每一个大约50行,从一个特定的网站中提取特定的信息。

    我对程序的第一次迭代是一个巨大的文件,它以一个网站为参数,如果它能识别这个网站并为它定制了代码(使用一个巨大的case语句来检查它是否能识别这个网站)。

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

    scrape.py --site google
    

    我希望文件结构类似于:

    scrape.py
    sites/
        google.py
        yahoo.py
        ...
        bing.py
    

    我还没有掌握对象定向,但我认识到这是在呼唤它,我所寻找的可能是一个通用的OO模式。

    对正确重构代码有帮助吗?

    PS-我看过《刮痧》,但它并不是我真正需要的,原因有很多。
    PPS-我不是在刮搜索网站,我是在刮美国法院网站。

    2 回复  |  直到 13 年前
        1
  •  4
  •   aaronasterling    13 年前

    您可以将代码放入 __init__ 方法获取配置的所有内容 _download 方法连接到该站点并下载它 _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对话,则可以创建 Downloader 在每个模块中初始化并使用它,就像 Parser 上课。如果有两个或多个解析器执行相同的操作,只需将它们定义为一个单独模块中的通用解析器,然后将其导入到需要它的每个站点的模块中。或者将其子类化以进行调整。如果不知道如何下载和解析网站,就很难更具体。

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

        2
  •  1
  •   pyfunc    13 年前

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

    弗斯特

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

    def ScrapeHandler(...):
        ...
    

    第二

    我将在sites目录中创建一个包含以下内容的初始化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(....)