4

我遇到了机械化以下链接的问题。这是我打算做的一个片段:

for link in mech.links(url_regex='/test/'):
    mech.follow_link(link)

    // Do some processing on that link

    mech.back()

根据机械化示例,这应该可以正常工作。然而事实并非如此。尽管调用了 .back(),循环结束,即使有更多的链接要访问。如果我注释掉 mech.follow_link(link) 和 mech.back(),用 print link.text 替换它们,它将打印出所有 50 个左右的链接。但是...一旦我取消注释 mech.follow_link,循环在第一个 follow_link 之后立即终止。back() 正在工作,如果我打印 mech.title(),然后调用 mech.back() 并再次打印 mech.title(),它会清楚地显示第一个标题,然后是“返回”页面的标题。我真的很困惑,这就是文档中的做法。不知道发生了什么。

4

3 回答 3

3

海盗,我同意,这不应该发生,您所做的几乎与 wwwsearch.sourceforge.net/mechanize/ 上的文档页面所说的一样;我尝试了与您类似的代码,并在第一次迭代后停止的地方得到了相同的结果。

但是,我确实找到了一种解决方法,即将来自 links() 的链接 URL 保存到一个列表中,然后按照该列表中的每个 URL:

from mechanize import Browser
br = Browser()
linklist = []
br.open(your_page_here)
for link in br.links(url_regex='/test/'): linklist.append(link.url)
for url in linklist:
    br.open(url)
    print br.title()

这很丑陋,你不应该这样做,但它似乎有效。

我对 mechanize 这样的 bugginess 并不感到兴奋(以及我在mechanize 处理两个提交按钮时遇到的问题),但它安装非常简单,看起来非常便携,并且可以离线运行(通过简单的 cron 作业)轻松比较到其他测试框架,如 Selenium ( seleniumhq dot org),看起来很棒,但实际设置和使用似乎更多。

于 2009-11-07T01:34:11.627 回答
1

比保存链接列表更直接的解决方法是简单地获取第二个 Browser 对象。这可以被认为等同于在“真实”浏览器中打开第二个选项卡。如果您还需要身份验证,则需要在浏览器实例之间共享一个 cookie jar:

import mechanize
import cookielib

br = mechanize.Browser()
br2 = mechanize.Browser()
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)
br2.set_cookiejar(cj)

br.open("http://yoursite.com/login")
br.select_form(nr=0)
br["username"] = "..."   # The hash keys are the names of the form fields
br["password"] = "..."
br.submit()    # This will save the authentication cookie to the shared cookie jar!
br.open("http://yoursite.com/page-to-parse")

for link in br.links(url_regex="/link_text"):
    req = br.click_link(url=link.url)
    html = br2.open(req).read()

请注意,必须从第一个实例中获取请求对象,然后与第二个实例一起提交。这相当于“真实”浏览器中的“在新窗口/标签中打开”命令。

于 2012-09-15T10:26:23.300 回答
0

每次页面访问都会将 links() 迭代器重置为该新页面上的链接。因此,您需要将其保存到单独的变量中,例如:links = mech.links(),或如 Chirael 指出的那样links = list(mech.links()),它的优点是可以用 来计算print >>sys.stderr, '# links: %d' % len(links)。这不是 mechanize.Browser 中的错误,它只是拥有有状态对象的副作用。

我在玩这个时注意到的另一个问题是,如果没有从一开始就设置,则不能使用mech.back()mech.request因为如果mech.set_response()用于设置原始页面内容则不会。在这种情况下,您必须明确地将第一个请求设置为:mech.request = mechanize.Request('about://config')。否则你会得到一个BrowserStateError: already at start of history.

并且为了完整起见,如果有人像我一样从谷歌搜索中来到这里,请确保将标题设置mechanize.make_response为,至少,(('content-type', 'text/html'),)或者mech.viewing_html将保留Falsemech.links()提高BrowserStateError("not viewing HTML").

于 2015-01-27T06:24:20.927 回答