将与网页进行交互,根据用户输入返回对应的内容。有些网站需要在登录后才能访问某个网页,在登录之前不允许访问。所以使用用户表单交互传递参数登录。
表单方法
HTML定义了两种向服务器提交数据的方法,分别是GET和POST。使用GET时,会将类似?name1=value1&name2=value2的数据添加到URL中,这串数据被称为“查询字符串”。由于浏览器存在URL长度限制,因此这种方法只适用于少量数据的场景。这种方法应当用于从服务器获取数据,而不是修改数据。在使用POST请求时,数据在请求体中发送,与URL保持分离。敏感数据只应使用POST请求进行发送,以免将数据暴露在URL中。POST数据在请求体中如何表示需要依赖所使用的编码类型。服务器还支持其他HTTP方法。
登录表单
登录这里写链接内容。需要用FirebugLite对这个表单进行分析。
包括几个重要组成部分,分别是form标签action、enctype和method属性,以及两个input域。action属性用于设置表单数据提交的地址,encytpe属性用于设置数据提交的编码。
当普通用户通过浏览器打开该网页时,需要输入邮箱和密码,然后单击按钮将数据提交到服务端。如果登录成功,则会跳转到主页;否则会跳转到登录页。
cookie
cookie某些网站为了辨明用户身份、进行session跟踪而储存在用户本地终端上的数据当普通用户加载登录表单时,_formkey的值将会保存在cookie中然后该值会与提交的登录表单数据种的_formkey值进行对比。
# coding:utf-8
import cookielib
import urllib
import urllib2
import lxml.html
# 用户邮箱
LOGTN_EMAIL='1486343178@qq.com'
#用户密码
LOGTN_PASSWORD='123456'
# 登录表单地址
LOGIN_URL='http://example.webscraping.com/places/default/user/login?_next=/places/default/index'
def login():
# 来捕获cookie并在后续连接请求时重新发送,创建cj处理器
cj=cookielib.CookieJar()
# 自定义opener,并将opener和CookieJar对象绑定
# urllib2.build_opener不同于urllib2.urlopen的是
# 它支持验证、cookie或者其他HTTP高级功能
opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
# 下载登录页面的源代码
html=opener.open(LOGIN_URL).read()
data=parse_form(html)
data['email']=LOGTN_EMAIL
data['password']=LOGTN_PASSWORD
# 获取数据的编码格式
encoded_data=urllib.urlencode(data)
# 给url发送请求和编码格式
request=urllib2.Request(LOGIN_URL,encoded_data)
# 获取响应
response=opener.open(request)
print response.geturl()
return opener
def parse_form(html):
"""从表单中获取输入的数据"""
tree=lxml.html.fromstring(html)
data={}
for e in tree.cssselect('form input'):
if e.get('name'):
data[e.get('name')]=e.get('value')
return data
if __name__=='__main__':
login()
从返回的URL地址可以看出服务器接受了提交的表单,response的URL是主页。
从浏览器加载cookie
先在浏览器中手工登录,然后使用之前的代码得到cookie,从而实现自动登录。以Firefox为例。Firefox在sqlite数据库中存储cookie,在JSON文件中存储session,都可以会获取。
不同的操作系统,Firefox存储session文件的位置不同。
- Linux:~/.mozilla/firefox/*.default/sessionstore.js
- OSX:~/Library/Application Support/Firefox/Profiles/*.default/sessionstore.js
- Window:%APPDATA%/Roaming/Mozilla/Firefox/Profiles/*.default/sessionstore.js
def login_firefox():
"""从Firefox中加载cookie"""
# 获取session缓存的文件路径
session_filename=find_ff_sessions()
#获取一个cookie处理器,包含登录用户的信息
cj=load_ff_sessions(session_filename)
opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
# 爬取主页信息,如果登录成功则会返回主页信息
html=opener.open(COUNTRY_URL).read()
# 检测是否登录成功
tree=lxml.html.fromstring(html)
print tree.cssselect('ul#navbar li a')[0].text_content()
return opener
def load_ff_sessions(session_filename):
cj=cookielib.CookieJar()
if os.path.exists(session_filename):
try:
json_data=json.loads(open(session_filename,'rb').read())
except ValueError as e:
print e
else:
for window in json_data.get('windows',[]):
for cookie in window.get('cookies',[]):
pprint.pprint(cookie)
c=cookielib.Cookie(0,cookie.get('name',''),
cookie.get('value',''),
None,False,
cookie.get('host',''),
cookie.get('host','').startswith('.'),
cookie.get('host','').startswith('.'),
cookie.get('path',''),False,False,
str(int(time.time())+3600*24*7),
False,None,None,{})
cj.set_cookie(c)
else:
print 'Session filename does not exist:',session_filename
return cj
def find_ff_sessions():
# 不同的操作系统Firefox中的session存储路径
paths=[
'~/.mozilla/firefox/*.default/sessionstore-backups',
'~/Library/Application Support/Firefox/Profiles/*.default',
'%APPDATA%/Roaming/Mozilla/Firefox/Profiles/*.default'
]
for path in paths:
filename=os.path.join(path,'*.js')
# 返回指定路径中所有匹配的文件
matches=glob.glob(os.path.expanduser(filename))
if matches:
return matches[0]
if __name__=='__main__':
login_firefox()
检测是否登录成功,在登录成功的主页面
检测结果:
支持内容更新的登录脚本扩展
自动化登录成功运行后,还可以继续扩展该脚本,时其与网站进行交互,更新国家数据。
编写一个脚本,每次运行时,都会使该国家的人口数量加1.
Edit_URL='http://example.webscraping.com/places/default/edit/Afghanistan-1'
opener=login()
country_html=opener.open(Edit_URL).read()
data=parse_form(country_html)
pprint.pprint(data)
更新数据
data['population']=int(data['population'])+1
encoded_data=urllib.urlencode(data)
request=urllib2.Request(Edit_URL,encoded_data)
response=opener.open(request)
可以对任意字段随意进行四ugai和测试。这里适用的表单技术可以应用于抓取时的复杂表单交互当中。
使用Mechanize模块实现自动表单处理
该模块提供了表单交互的高级接口。
import mechanize
edit_url='http://example.webscraping.com/places/default/edit/Afghanistan-1'
# 打开浏览器
br=mechanize.Browser()
br.open(LOGIN_URL)
# 选择表单
br.select_form(nr=0)
br['email']=LOGTN_EMAIL
br['password']=LOGTN_PASSWORD
# 提交
response=br.submit()
br.open(edit_url)
br.select_form(nr=0)
br['population']=str(int(br['population'])+1)
br.submit()
不再需要管理cookie,而且访问表单输入框也更加容易处理。
首先创建一个Mechanize浏览器对象,然后定位到登录URL,选择登录表单。直接向浏览器对象传递名称和值,来设置选定表单的输入框内容。然后定位到国家编辑页面,使用表单增加人数。