可以将更强大的HTML解析器连接到Python mechanize吗?
我正在尝试使用mechanize这个工具在一个网站上解析并提交一个表单,但它似乎无法识别这个表单和里面的元素。我怀疑是因为这个网站的HTML代码写得不好,导致mechanize处理不了。我想先用一个更擅长处理糟糕HTML的解析器(比如lxml或BeautifulSoup)来清理这些代码,然后再把处理好的内容交给表单解析器。因为我不仅需要mechanize来提交表单,还需要它来保持会话(我是在登录状态下操作这个表单的)。
我不太确定该怎么做,如果这确实可行的话……我对HTTP协议的各种细节不是很熟悉,不太清楚怎么把不同的部分结合在一起。有没有什么建议?
3 个回答
你想要的功能可以通过 lxml.etree
来实现,它是 xml.etree.ElementTree
的一个替代品,属于 lxml
库的一部分。
首先,我们来看看一些格式不太正确的 HTML:
% cat bad.html
<html>
<HEAD>
<TITLE>this HTML is awful</title>
</head>
<body>
<h1>THIS IS H1</H1>
<A HREF=MYLINK.HTML>This is a link and it is awful</a>
<img src=yay.gif>
</body>
</html>
(注意开闭标签的大小写混合,还有缺少的引号)。
然后我们对它进行解析:
>>> from lxml import etree
>>> bad = file('bad.html').read()
>>> html = etree.HTML(bad)
>>> print etree.tostring(html)
<html><head><title>this HTML is awful</title></head><body>
<h1>THIS IS H1</h1>
<a href="MYLINK.HTML">This is a link and it is awful</a>
<img src="yay.gif"/></body></html>
你会发现标签和引号都被自动修正了。
如果你之前在解析 HTML 时遇到问题,这可能就是你需要的解决方案。至于 HTTP 的细节,那是另一个话题了。
我遇到一个问题,就是一个表单的字段缺失了。我找了半天没发现有什么错误的HTML代码,但我觉得这可能是问题的原因,所以我用了BeautifulSoup的prettify功能来解析它,结果成功了。
resp = br.open(url)
soup = BeautifulSoup(resp.get_data())
resp.set_data(soup.prettify())
br.set_response(resp)
我很想知道怎么能自动做到这一点。
编辑:我找到了自动实现的方法。
class PrettifyHandler(mechanize.BaseHandler):
def http_response(self, request, response):
if not hasattr(response, "seek"):
response = mechanize.response_seek_wrapper(response)
# only use BeautifulSoup if response is html
if response.info().dict.has_key('content-type') and ('html' in response.info().dict['content-type']):
soup = BeautifulSoup(response.get_data())
response.set_data(soup.prettify())
return response
# also parse https in the same way
https_response = http_response
br = mechanize.Browser()
br.add_handler(PrettifyHandler())
br
现在会使用BeautifulSoup
来解析所有包含HTML的响应,这些响应的内容类型(mime类型)是text/html
。
在mechanize网站的第一页上,有一个很大的例子:
# Sometimes it's useful to process bad headers or bad HTML:
response = br.response() # this is a copy of response
headers = response.info() # currently, this is a mimetools.Message
headers["Content-type"] = "text/html; charset=utf-8"
response.set_data(response.get_data().replace("<!---", "<!--"))
br.set_response(response)
所以看起来可以用另一个解析器先处理一下响应,这样就能生成格式正确的HTML,然后再把它交给mechanize进行进一步处理。