Python HTML解析标签内的特定信息

时间:2011-04-10 22:19:52

标签: python html parsing tags

我正在尝试解析标签中的特定信息。

例如,在网站上:

http://www.epicurious.com/articlesguides/bestof/toprecipes/bestchickenrecipes/recipes/food/views/My-Favorite-Simple-Roast-Chicken-231348

我正在尝试解析非常具体的信息,例如成分。如果您转到pagesource,您可以看到存在的信息位于名为

的标记内

<h2>Ingredients</h2><ul class="ingredientsList">具有所有实际成分。

我在网上发现了一个python程序,可以方便地解析网站中的超链接。但我想修改它来解析这些成分。我对python不太熟悉,但我究竟会如何修改我的代码以满足我的解析需求呢?

请详细说明我应该如何做到这一点或提供示例等,因为我对此不太了解,所以非常感谢。

代码:

import sgmllib

class MyParser(sgmllib.SGMLParser):
    "A simple parser class."

    def parse(self, s):
        "Parse the given string 's'."
        self.feed(s)
        self.close()

    def __init__(self, verbose=0):
        "Initialise an object, passing 'verbose' to the superclass."

        sgmllib.SGMLParser.__init__(self, verbose)
        self.hyperlinks = []
        self.descriptions = []
        self.inside_a_element = 0
        self.starting_description = 0

    def start_a(self, attributes):
        "Process a hyperlink and its 'attributes'."

        for name, value in attributes:
            if name == "href":
                self.hyperlinks.append(value)
                self.inside_a_element = 1
                self.starting_description = 1

    def end_a(self):
        "Record the end of a hyperlink."

        self.inside_a_element = 0

    def handle_data(self, data):
        "Handle the textual 'data'."

        if self.inside_a_element:
            if self.starting_description:
                self.descriptions.append(data)
                self.starting_description = 0
            else:
                self.descriptions[-1] += data

    def get_hyperlinks(self):
        "Return the list of hyperlinks."

        return self.hyperlinks

    def get_descriptions(self):
        "Return a list of descriptions."

        return self.descriptions

import urllib, sgmllib

# Get something to work with.
f = urllib.urlopen("http://www.epicurious.com/Roast-Chicken-231348")
s = f.read()

# Try and process the page.
# The class should have been defined first, remember.
myparser = MyParser()
myparser.parse(s)

# Get the hyperlinks.
print myparser.get_hyperlinks()
print myparser.get_descriptions()

2 个答案:

答案 0 :(得分:3)

查看http://www.crummy.com/software/BeautifulSoup/您的方法适用于简单案例,但只要html和/或您的要求变得更复杂,就会让您感到头疼。

答案 1 :(得分:1)

我会听到所有人说滴滴涕无法分析HTML文本。

好的,好的,但我在五十分钟内得到了结果:

首先,我使用此代码来方便地显示网页的代码源:

import urllib

url = ('http://www.epicurious.com/articlesguides/bestof/'
       'toprecipes/bestchickenrecipes/recipes/food/views/'
       'My-Favorite-Simple-Roast-Chicken-231348')


sock = urllib.urlopen(url)
ch = sock.read()
sock.close()


gen = (str(i)+' '+repr(line) for i,line in enumerate(ch.splitlines(1)))

print '\n'.join(gen)

然后,抓住成分是孩子的游戏:

import urllib
import re

url = ('http://www.epicurious.com/articlesguides/bestof/'
       'toprecipes/bestchickenrecipes/recipes/food/views/'
       'My-Favorite-Simple-Roast-Chicken-231348')

sock = urllib.urlopen(url)
ch = sock.read()
sock.close()

x = ch.find('ul class="ingredientsList">')

patingr = re.compile('<li class="ingredient">(.+?)</li>\n')

print patingr.findall(ch,x)

修改

Achim的,

关于'\ n'的存在,故障是我的,而不是正则表达式工具:我写的代码太快了。

关于大写你是对的:BS仍然找到正确的字符串,而正则表达式失败。但是,我从未见过使用大写字母编写元素标签的源代码。你能给我一个这样的链接吗?

关于'",它是相同的,我从未见过,但你是对的,可能会发生。

但是,在编写RE时,如果在某些地方有大写字母或'而不是",则会写入RE以匹配它们:问题在哪里?< / p>

您的意思是:如果源代码发生变化?有一天,如果某个网站的源代码会从小写更改为大写,或"更改为',则更不可能。这不太现实。

所以,很容易纠正我的RE

import urllib
import re

url = ('http://www.epicurious.com/articlesguides/bestof/'
       'toprecipes/bestchickenrecipes/recipes/food/views/'
       'My-Favorite-Simple-Roast-Chicken-231348')

sock = urllib.urlopen(url)
ch = sock.read()
sock.close()

#----------------------------------------------------------
patingr = re.compile('<li class="ingredient">(.+?)</li>\n')
print
print '\n'.join(repr(mat.group()) for mat in patingr.finditer(ch))


ch = ch.replace('<li class="ingredient">One 2- to 3-pound farm-raised chicken</li>',
                "<LI class='ingredient'>One 2- to 3-pound farm-raised \nchicken</li>")
print
print '\n'.join(repr(mat.group()) for mat in patingr.finditer(ch))


patingr = re.compile('<li class=["\']ingredient["\']>(.+?)</li>\n',re.DOTALL|re.IGNORECASE)
print
print '\n'.join(repr(mat.group()) for mat in patingr.finditer(ch))

结果

'<li class="ingredient">One 2- to 3-pound farm-raised chicken</li>\n'
'<li class="ingredient">Kosher salt and freshly ground black pepper</li>\n'
'<li class="ingredient">2 teaspoons minced thyme (optional)</li>\n'
'<li class="ingredient">Unsalted butter</li>\n'
'<li class="ingredient">Dijon mustard</li>\n'

'<li class="ingredient">Kosher salt and freshly ground black pepper</li>\n'
'<li class="ingredient">2 teaspoons minced thyme (optional)</li>\n'
'<li class="ingredient">Unsalted butter</li>\n'
'<li class="ingredient">Dijon mustard</li>\n'

"<LI class='ingredient'>One 2- to 3-pound farm-raised \nchicken</li>\n"
'<li class="ingredient">Kosher salt and freshly ground black pepper</li>\n'
'<li class="ingredient">2 teaspoons minced thyme (optional)</li>\n'
'<li class="ingredient">Unsalted butter</li>\n'
'<li class="ingredient">Dijon mustard</li>\n'

然后,从现在开始,我将始终在标签中添加标志re.IGNORECASE和["']

是否还会出现其他“问题”?我很想知道它们。

我不假装必须在所有情况下使用正则表达式并且解析器永远不会使用,我只是认为如果验证以控制和分隔方式使用正则表达式的条件,它们是非常有用的,它将是一个可惜忽略了它们。

顺便说一句,你没有说正则表达式比BeautifulSoup快得多。见time comparison between regex an BeautifulSoup