6

私は現在、使用されるメモリの量を減らすために、非常に大きなHTMLドキュメント(私は知っています..yuck)を繰り返し解析しようとしています。私が抱えている問題は、次のようなXML構文エラーが発生することです。

lxml.etree.XMLSyntaxError: Attribute name redefined, line 134, column 59

これにより、すべてが停止します。

構文エラーを抑えずにHTMLを繰り返し解析する方法はありますか?

現時点では、XML構文エラー例外から行番号を抽出し、その行をドキュメントから削除してから、プロセスを再開しています。かなり嫌な解決策のようです。もっと良い方法はありますか?

編集:

これは私が現在行っていることです:

context = etree.iterparse(tfile, events=('start', 'end'), html=True)
in_table = False
header_row = True
while context:
    try:
        event, el = context.next()

        # do something

        # remove old elements
        while el.getprevious() is not None:
            del el.getparent()[0]

    except etree.XMLSyntaxError, e:
        print e.msg
        lineno = int(re.search(r'line (\d+),', e.msg).group(1))
        remove_line(tfilename, lineno)
        tfile = open(tfilename)
        context = etree.iterparse(tfile, events=('start', 'end'), html=True)
    except KeyError:
        print 'oops keyerror'
4

5 に答える 5

8

完璧な解決策は、Python独自のHTMLParser [ドキュメント]になりました。

これは私が使用することになった(かなり悪い)コードです:

class MyParser(HTMLParser):
    def __init__(self):
        self.finished = False
        self.in_table = False
        self.in_row = False
        self.in_cell = False
        self.current_row = []
        self.current_cell = ''
        HTMLParser.__init__(self)

    def handle_starttag(self, tag, attrs):
        attrs = dict(attrs)
        if not self.in_table:
            if tag == 'table':
                if ('id' in attrs) and (attrs['id'] == 'dgResult'):
                    self.in_table = True
        else:
            if tag == 'tr':
                self.in_row = True
            elif tag == 'td':
                self.in_cell = True
            elif (tag == 'a') and (len(self.current_row) == 7):
                url = attrs['href']
                self.current_cell = url


    def handle_endtag(self, tag):
        if tag == 'tr':
            if self.in_table:
                if self.in_row:
                    self.in_row = False
                    print self.current_row
                    self.current_row = []
        elif tag == 'td':
            if self.in_table:
                if self.in_cell:
                    self.in_cell = False
                    self.current_row.append(self.current_cell.strip())
                    self.current_cell = ''

        elif (tag == 'table') and self.in_table:
            self.finished = True

    def handle_data(self, data):
        if not len(self.current_row) == 7:
            if self.in_cell:
                self.current_cell += data

そのコードで私はこれを行うことができます:

parser = MyParser()
for line in myfile:
    parser.feed(line)
于 2011-12-13T04:18:23.987 に答える
5

現時点では、lxmletree.iterparseはキーワード引数recover= Trueをサポートしているため、壊れたhtmlを修正するHTMLParserのカスタムサブクラスを作成する代わりに、この引数をiterparseに渡すことができます。

巨大で壊れたhtmlを適切に解析するには、次の手順を実行するだけです。

etree.iterparse(tfile, events=('start', 'end'), html=True, recover=True)
于 2015-08-17T11:52:16.280 に答える
1

iterparseの引数と。に使用Trueします。htmlhuge_tree

于 2011-12-12T17:09:52.777 に答える
0

古い質問を再ハッシュして申し訳ありませんが、解決策を探している後発者のために、 Lxml3.3には増分解析を行うHTMLPullParserとXMLPullParserがあります。その他の例については、構文解析のLxmlの概要を確認することもできます。

OPが言うように、非常に大きなドキュメントを解析する必要があり、メモリの節約が必要な場合は、要素ツリーの構築を回避するために、イベントハンドラーとしてカスタムクラスを作成できます。何かのようなもの:

class MyParserTarget:
    def start(self, tag, attrib, nsmap) -> None:
        # do something
    def end((self, tag) -> None:
        # do something
    def data(self, data) -> None:
        # do something
    def close(self):
        # return your result

mytarget = MyParserTarget()
parser = lxml.etree.HTMLPullParser(target=mytarget)
parser.feed(next(content))
# Do other stuff
result = parser.close()
于 2021-08-18T14:39:20.053 に答える
-1

lxml.htmlを使用してHTMLドキュメントを解析してみてください。

バージョン2.0以降、lxmlにはHTMLを処理するための専用のPythonパッケージlxml.htmlが付属しています。これはlxmlのHTMLパーサーに基づいていますが、HTML要素用の特別なElement APIと、一般的なHTML処理タスク用の多数のユーティリティを提供します。

于 2011-12-12T16:51:47.530 に答える