介绍
MechanicalSoup的定位是功能性的网页抓取和交互库。它最大的特点是可以和网页交互,填充一些表单。它的底层使用的是BeautifulSoup(也就是bs4)和requests库,因此如果你熟悉后两个库,这个库上手会很容易。MechanicalSoup的主页是https://mechanicalsoup.readthedocs.io/,目前没有官方中文文档。
简单的例子
这里翻译一个官方文档上的教程:MechanicalSoup tutorial。
第一次接触,一点点深入
作为一个简单的例子,我们将访问<http://httpbin.org/,它是一个设计用来测试类似MechanicalSoup的工具的网站。
首先,让我们新建一个浏览器(browser)对象:
>>> import mechanicalsoup
>>> browser = mechanicalsoup.StatefulBrowser()
要自定义新建browser的方式(比如说修改user-agent、选择HTML解析器、响应404 Not Found错误的方式等等),请查阅__init__()
。
现在,打开我们想要的网页:
>>> browser.open("http://httpbin.org/")
<Response [200]>
open()
的返回值是一个类型为requests.Response的对象。事实上,MechanicalSoup使用了requests库实际对网站发送请求,因此收到这样的对象类型我们一点也不奇怪。简单来说,它包含了服务器返回的数据(data)和元数据(meta-data)。你可以看到HTTP返回码是200,这表示“OK”,这个对象同时也包含了所有我们刚刚下载的页面内容。
和一个正常的浏览器地址栏一样,browser会记住正在使用的URL:
>>> browser.get_url()
'http://httpbin.org/'
现在,让我们将链接指向/form/post
:
>>> browser.follow_link("forms")
<Response [200]>
>>> browser.get_url()
'http://httpbin.org/forms/post'
我们向follow_link()
中传入了一个正则表达式"forms"
,它会找到一个文本符合这个正则式的链接。调用follow_link()
有很多其他方法,但我们以后再谈。
现在我们正在访问http://httpbin.org/forms/post, 这个页面包含一个表单。让我们看一下页面内容:
>>> browser.get_current_page()
<!DOCTYPE html>
<html>
...
<form action="/post" method="post">
...
事实上,get_current_page()
返回的类型是bs4.BeautifulSoup。BeautifulSoup,也就是bs4,是Mechanicalsoup使用的第二个库:它是一个HTML操作库。现在你可以使用BeautifulSoup来在页面的标签之间跳转。比如说,获得所有的<legend>
标签:
>>> browser.get_current_page().find_all('legend')
[<legend> Pizza Size </legend>, <legend> Pizza Toppings </legend>]
要填充一个表单,我们要告诉MechanicalSoup我们需要填写和提交的表单位置:
>>> browser.select_form('form[action="/post"]')
select_form()
的参数是一个CSS选择器。这里我们选择了所有名为form
且带一个属性名为action
值为"/post“
的HTML标签。由于这个页面里只有一张表单,使用browser.select_form()
也可以取巧的得到这个表单。
现在,给表单的字段赋值。首先,有哪些可用的字段呢?你可以使用print_summary()
来打印当前被选择的表单的摘要:
>>> browser.get_current_form().print_summary()
<input name="custname"/>
<input name="custtel" type="tel"/>
<input name="custemail" type="email"/>
<input name="size" type="radio" value="small"/>
<input name="size" type="radio" value="medium"/>
<input name="size" type="radio" value="large"/>
<input name="topping" type="checkbox" value="bacon"/>
<input name="topping" type="checkbox" value="cheese"/>
<input name="topping" type="checkbox" value="onion"/>
<input name="topping" type="checkbox" value="mushroom"/>
<input max="21:00" min="11:00" name="delivery" step="900" type="time"/>
<textarea name="comments"></textarea>
处理文本字段很简单:只需要根据input
元素的name
属性,给它们赋值就行了。
>>> browser["custname"] = "Me"
>>> browser["custtel"] = "00 00 0001"
>>> browser["custemail"] = "nobody@example.com"
>>> browser["comments"] = "This pizza looks really good :-)"
对于单选按钮,也很简单:单选按钮有一些包含相同name
不同值的input
标签,你只需要选择你想要那个就行了(我们这里要选择的是name
属性为"size"
,value
属性是"medium"
的元素):
>>> browser["size"] = "medium"
对于选择按钮,使用的是和单选按钮一样的机制:
>>> browser["topping"] = "bacon"
但我们也可以通过赋值一个列表给字段来选择多个选择框:
>>> browser["topping"] = ("bacon", "cheese")
事实上,browser["..."] = "..."
(比如调用__setitem__()
)只是一个填充表单的助手,你可以使用任何BeautifulSoup提供的工具来修改soup对象,MechanicalSoup会负责为你进行表单提交。
让我们看看填充好的表单时什么样的:
>>> browser.launch_browser()
lauch_browser()
会启动一个真实的web浏览器来访问我们browser
对象的页面,包括我们刚刚对表单所做的改变(注意它不会打开一个真正的web页面,但是会创建一个包含页面内容的临时文件并将browser指向这个页面)。尝试选择其他的方框和文本字段的内容并重新载入browser。
结合浏览器的web开发工具,这个方法会变得非常有用。举个例子,在Firefox里,右键选择”检查元素“,你可以获取到修改一个字段所需要的全部信息(具体来说就是name
和value
属性)。
使用print_summary()
来检查新的内容也是可以的(我们已经在列出字段时使用过了):
>>> browser.get_current_form().print_summary()
<input name="custname" value="Me"/>
<input name="custtel" type="tel" value="00 00 0001"/>
<input name="custemail" type="email" value="nobody@example.com"/>
<input name="size" type="radio" value="small"/>
<input checked="" name="size" type="radio" value="medium"/>
<input name="size" type="radio" value="large"/>
<input checked="" name="topping" type="checkbox" value="bacon"/>
<input checked="" name="topping" type="checkbox" value="cheese"/>
<input name="topping" type="checkbox" value="onion"/>
<input name="topping" type="checkbox" value="mushroom"/>
<input max="21:00" min="11:00" name="delivery" step="900" type="time"/>
<textarea name="comments">This pizza looks really good :-)</textarea>
假设我们已经对当前的表单内容满意了,我们可以提交它(比如说,模拟点击提交按钮):
>>> response = browser.submit_selected()
它返回的不再是一个HTML页面,因此browser不会把它解析成一个BeautifulSoup对象,但是我们仍然可以看到它包含的内容:
>>> print(response.text)
{
"args": {},
"data": "",
"files": {},
"form": {
"comments": "This pizza looks really good :-)",
"custemail": "nobody@example.com",
"custname": "Me",
"custtel": "00 00 0001",
"delivery": "",
"size": "medium",
"topping": [
"bacon",
"cheese"
]
},
...
这里是完整的例子(examples/expl_httpbin.py):
import mechanicalsoup
browser = mechanicalsoup.StatefulBrowser()
browser.open("http://httpbin.org/")
print(browser.get_url())
browser.follow_link("forms")
print(browser.get_url())
print(browser.get_current_page())
browser.select_form('form[action="/post"]')
browser["custname"] = "Me"
browser["custtel"] = "00 00 0001"
browser["custemail"] = "nobody@example.com"
browser["size"] = "medium"
browser["topping"] = "onion"
browser["topping"] = ("bacon", "cheese")
browser["comments"] = "This pizza looks really good :-)"
# Uncomment to launch a real web browser on the current page.
# browser.launch_browser()
# Uncomment to display a summary of the filled-in form
# browser.get_current_form().print_summary()
response = browser.submit_selected()
print(response.text)
网友评论