【问题标题】:Slow html parser. How to increase the speed?慢速 html 解析器。如何提高速度?
【发布时间】:2014-04-01 14:52:17
【问题描述】:

我想估计新闻对道琼斯报价的影响。为此,我使用 beutifullsoup 库编写了 Python html 解析器。我提取一篇文章并将其存储在 XML 文件中,以便使用 NLTK 库进行进一步分析。如何提高解析速度?下面的代码完成了所需的任务,但速度非常慢。

这里是html解析器的代码:

import urllib2
import re
import xml.etree.cElementTree as ET
import nltk
from bs4 import BeautifulSoup
from datetime import date
from dateutil.rrule import rrule, DAILY
from nltk.corpus import stopwords
from collections import defaultdict

def main_parser():
    #starting date
    a = date(2014, 3, 27)
    #ending date
    b = date(2014, 3, 27)
    articles = ET.Element("articles")
    f = open('~/Documents/test.xml', 'w')
    #loop through the links and per each link extract the text of the article, store the latter at xml file
    for dt in rrule(DAILY, dtstart=a, until=b):
        url = "http://www.reuters.com/resources/archive/us/" + dt.strftime("%Y") + dt.strftime("%m") + dt.strftime("%d") + ".html"
        page = urllib2.urlopen(url)
        #use html5lib ??? possibility to use another parser
        soup = BeautifulSoup(page.read(), "html5lib")
        article_date = ET.SubElement(articles, "article_date")
        article_date.text = str(dt)
        for links in soup.find_all("div", "headlineMed"):
            anchor_tag = links.a
            if not 'video' in anchor_tag['href']:
                try:
                    article_time = ET.SubElement(article_date, "article_time")
                    article_time.text = str(links.text[-11:])

                    article_header = ET.SubElement(article_time, "article_name")
                    article_header.text = str(anchor_tag.text)

                    article_link = ET.SubElement(article_time, "article_link")
                    article_link.text = str(anchor_tag['href']).encode('utf-8')

                    try:
                        article_text = ET.SubElement(article_time, "article_text")
                        #get text and remove all stop words
                        article_text.text = str(remove_stop_words(extract_article(anchor_tag['href']))).encode('ascii','ignore')
                    except Exception:
                        pass
                except Exception:
                    pass

    tree = ET.ElementTree(articles)
    tree.write("~/Documents/test.xml","utf-8")

#getting the article text from the spicific url
def extract_article(url):
    plain_text = ""
    html = urllib2.urlopen(url).read()
    soup = BeautifulSoup(html, "html5lib")
    tag = soup.find_all("p")
    #replace all html tags
    plain_text = re.sub(r'<p>|</p>|[|]|<span class=.*</span>|<a href=.*</a>', "", str(tag))
    plain_text = plain_text.replace(", ,", "")
    return str(plain_text)

def remove_stop_words(text):
    text=nltk.word_tokenize(text)
    filtered_words = [w for w in text if not w in stopwords.words('english')]
    return ' '.join(filtered_words)

【问题讨论】:

    标签: python html performance parsing html-parsing


    【解决方案1】:

    可以应用多个修复(无需更改您当前使用的模块):

    • 使用 lxml 解析器而不是 html5lib - 速度要快得多(而且还要快 3 倍)
    • 仅使用SoupStrainer 解析文档的一部分(注意html5lib 不支持SoupStrainer - 它总是会缓慢解析整个文档)

    以下是更改后代码的外观。简短的性能测试显示至少提升了 3 倍:

    import urllib2
    import xml.etree.cElementTree as ET
    from datetime import date
    
    from bs4 import SoupStrainer, BeautifulSoup
    import nltk
    from dateutil.rrule import rrule, DAILY
    from nltk.corpus import stopwords
    
    
    def main_parser():
        a = b = date(2014, 3, 27)
        articles = ET.Element("articles")
        for dt in rrule(DAILY, dtstart=a, until=b):
            url = "http://www.reuters.com/resources/archive/us/" + dt.strftime("%Y") + dt.strftime("%m") + dt.strftime(
                "%d") + ".html"
    
            links = SoupStrainer("div", "headlineMed")
            soup = BeautifulSoup(urllib2.urlopen(url), "lxml", parse_only=links)
    
            article_date = ET.SubElement(articles, "article_date")
            article_date.text = str(dt)
            for link in soup.find_all('a'):
                if not 'video' in link['href']:
                    try:
                        article_time = ET.SubElement(article_date, "article_time")
                        article_time.text = str(link.text[-11:])
    
                        article_header = ET.SubElement(article_time, "article_name")
                        article_header.text = str(link.text)
    
                        article_link = ET.SubElement(article_time, "article_link")
                        article_link.text = str(link['href']).encode('utf-8')
    
                        try:
                            article_text = ET.SubElement(article_time, "article_text")
                            article_text.text = str(remove_stop_words(extract_article(link['href']))).encode('ascii', 'ignore')
                        except Exception:
                            pass
                    except Exception:
                        pass
    
        tree = ET.ElementTree(articles)
        tree.write("~/Documents/test.xml", "utf-8")
    
    
    def extract_article(url):
        paragraphs = SoupStrainer('p')
        soup = BeautifulSoup(urllib2.urlopen(url), "lxml", parse_only=paragraphs)
        return soup.text
    
    
    def remove_stop_words(text):
        text = nltk.word_tokenize(text)
        filtered_words = [w for w in text if not w in stopwords.words('english')]
        return ' '.join(filtered_words)
    

    请注意,我已经从 extract_article() 中删除了正则表达式处理 - 看起来您可以从 p 标签中获取整个文本。

    我可能引入了一些问题 - 请检查一切是否正确。


    另一种解决方案是使用lxml 处理从解析(替换beautifulSoup)到创建xml(替换xml.etree.ElementTree)的所有内容。


    另一个解决方案(绝对是最快的)是切换到Scrapy web-scraping web-framework。 它很简单而且非常快。有各种各样的电池,你可以想象,包括在内。例如,有链接提取器、XML 导出器、数据库管道等。值得一看。

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      您想选择最好的解析器。

      我们在构建时对大多数解析器/平台进行基准测试:http://serpapi.com

      这是一篇关于 Medium 的完整文章: https://medium.com/@vikoky/fastest-html-parser-available-now-f677a68b81dd

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-21
        • 2012-04-24
        • 2011-08-03
        • 1970-01-01
        • 1970-01-01
        • 2011-08-12
        • 2021-08-29
        • 1970-01-01
        相关资源
        最近更新 更多