我遇到机械化跟随链接的问题。这是我想要做的事情的片段:
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(),它会清楚地显示第一个标题,然后是“后退”页面的标题。我真的很困惑,这就是它在文档中的表现。不知道发生了什么。
答案 0 :(得分:2)
Pirate,我同意,这不应该发生,你正在做的很像wwwsearch.sourceforge.net/mechanize/上的文档页面;我尝试了类似于你的代码,并在第一次迭代后停止了相同的结果。
但是,我确实找到了解决办法,即将link()中的链接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 handling two submit buttons poorly的一个问题),我不是很兴奋机械化,但它安装非常简单,看起来非常便携,并且可以脱机运行(通过简单的cron作业)很容易与其他测试框架比较,比如Selenium(seleniumhq dot org),它看起来很棒但似乎更多参与来实际设置和使用。
答案 1 :(得分: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()
请注意,必须从第一个实例获取请求对象,然后使用第二个实例提交它。这相当于“真实”浏览器中的“在新窗口/选项卡中打开”命令。
答案 2 :(得分: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'),)
或{{1将保持mech.viewing_html
而False
将会mech.links()
。