我正在使用html.parser和urllib.request。我不打算使用任何非原生模块,但如果有必要,我愿意使用其他原生模块。 目前(部分)我的代码如下所示:
class MyHTMLParser(HTMLParser):
def handle_data(self, data):
if self.getpos()[0] == 167:
print(self.data)
我遇到的问题是HTMLParser.getpos总是返回一个(1,x)的元组,其中x是一个每次增加的数字,但看起来是随机的),如下所示:
(1, 21) (1, 41) (1, 51) (1, 77) (1, 134) (1, 206) (1, 406) (1, 509) (1, 553) (1, 627) (1, 680) (1, 784) (1, 1143) (1, 1368)
我觉得整个html.parser模块都是以非常愚蠢的方式编写的,本来可以想得更好。显然它有效,但这是违反直觉的。
完整代码:
from urllib.request import *
from html.parser import HTMLParser
class MyHTMLParser(HTMLParser):
def handle_data(self, data):
print(self.getpos())
if self.getpos()[0] == 167:
print(data)
parser = MyHTMLParser()
html = urlopen("https://www.azlyrics.com/lyrics/aha/takeonme.html").read()
parser.feed(str(html))
答案 0 :(得分:0)
关于如何从div中解析数据 - 您应该在输入div并退出div时进行跟踪,并在这些点之间累积数据。这对于库来说很容易,并且与实际的解析相比更接近,尽管我不打算讨论什么是愚蠢的,什么不是。
您的行号问题是因为您使用str
来阅读bytes
个对象。在解释器中,您可以看到为什么这是一个问题:
>>> str(b"ab\nc")
"b'ab\\nc'"
它实际上并没有将它转换为一种等效字符串,而是转换为字符串表示形式。这意味着bytes对象中的换行符字面上表示为\n
,因此您没有得到任何行号。要解码字节对象,您应该使用.decode
。以下代码应该有效:
import sys
from html.parser import HTMLParser
from urllib.request import urlopen
class LyricParser(HTMLParser):
def get_lyrics(self, html):
self.read_lyrics = False
self.lyrics = []
self.feed(html)
return "".join(self.lyrics)
def handle_starttag(self, tag, attrs):
if tag == "div" and self.getpos()[0] == 167:
self.read_lyrics = True
def handle_data(self, data):
if self.read_lyrics:
self.lyrics.append(data)
def handle_endtag(self, tag):
if tag == "div":
self.read_lyrics = False
parser = LyricParser()
page = urlopen("https://www.azlyrics.com/lyrics/aha/takeonme.html")
lyrics = parser.get_lyrics(page.read().decode('utf-8'))
print(lyrics)
对我而言,这正确输出如下内容:
Talking away
I don't know what I'm to say
I'll say it anyway
Today's another day to find you
...
看过这个页面我必须得出结论你是对的 - 它的结构很棒,识别歌词div的唯一方法是按行号,或者前一个div的数量 - 如果行号失败,你可以尝试在handle_starttag
中保持div的计数。