示例代码:
html = """
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title heretitle>
head>
<frameset rows="70%,*">
<frame bordercolor="1" src="04_table.html" noresize="noresize" />
<frameset cols="20%,*">
<frame bordercolor="1" src="layout/b.html" noresize="noresize" />
<frame bordercolor="1" noresize="noresize" name="content" />
frameset>
frameset>
<body>
<a href="http://www.baidu.com" class="hehe" id="link1">a>
body>
html>
"""
bs=BeautifulSoup(html,"lxml")
In [22]: bs.head
Out[22]: \n"text/html; charset=unicode-escape" http-equiv="Content-Type"/>\nInsert title here \n
In [23]: print type(bs.head)
'bs4.element.Tag'>
In [24]: bs.name
Out[24]: u'[document]'
In [25]: bs.head.name
Out[25]: 'head'
In [26]: bs.a.attrs
Out[26]: {'class': ['hehe'], 'href': 'http://www.baidu.com', 'id': 'link1'}
In [27]: bs.a['class']
Out[27]: ['hehe']
In [31]: bs.a['class']="haha" #修改属性
In [32]: bs.a['class']
Out[32]: 'haha'
In [33]: del bs.a['class']
In [34]: bs.a.attrs
Out[34]: {'href': 'http://www.baidu.com', 'id': 'link1'}
In [45]: bs.title.string #.string获取标签内容
Out[45]: u'Insert title here'
In [46]: print type(bs.title.string)
<class 'bs4.element.NavigableString'>
In [38]: bs.name
Out[38]: u'[document]'
In [39]: print type(bs.name)
'unicode'>
In [40]: bs.attrs
Out[40]: {}
In [41]: # 文档本身属性为空
In [35]: bs.a.string #获取a标签内文字
Out[35]: u' hehehe '
In [36]: print type(bs.a.string)
<class 'bs4.element.Comment'>
In [52]: bs.frameset.contents
Out[52]:
[u'\n',
"1" noresize="noresize" src="04_table.html"/>,
u'\n',
,
u'\n']
In [53]: bs.frameset.contents[3]
Out[53]:
节点内容:.string属性
如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点。如果一个tag仅有一个子节点,那么这个tag也可以使用 .string 方法,输出结果与当前唯一子节点的 .string 结果相同。
通俗点说就是:如果一个标签里面没有标签了,那么 .string 就会返回标签里面的内容。如果标签里面只有唯一的一个标签了,那么 .string 也会返回最里面的内容
find_all(name, attrs, recursive, text, **kwargs)
name参数可以传字符串、正则表达式、列表。
text 参数可以搜搜文档中的字符串内容,与 name 参数的可选值一样, text 参数接受 字符串 , 正则表达式 , 列表
In [93]: bs.find_all('a')
Out[93]: [<a class="hehe" href="http://www.baidu.com" id="link1">a>]
In [94]:
In [94]: bs.find_all(['a','title'])
Out[94]:
[<title>Insert title heretitle>,
<a class="hehe" href="http://www.baidu.com" id="link1">a>]
In [95]:
In [95]: bs.find_all(id="link1")
Out[95]: [<a class="hehe" href="http://www.baidu.com" id="link1">a>]
In [96]:
In [96]: bs.find_all(text="hehehe")
Out[96]: []
In [97]: bs.find_all(text="Insert title here")
Out[97]: [u'Insert title here']
In [98]: import re
In [99]: bs.find_all(text=re.compile("Insert title"))
Out[99]: [u'Insert title here']
In [83]: bs.select('title') #通过标签名查找
Out[83]: [Insert title here ]
In [84]: bs.select('.hehe') #通过类名查找
Out[84]: ["hehe" href="http://www.baidu.com" id="link1">-- hehehe -->]
In [85]: bs.select('#link1') #通过id查找
Out[85]: ["hehe" href="http://www.baidu.com" id="link1">-- hehehe -->]
In [86]: bs.select('head > title') #查找head标签下title标签
Out[86]: [Insert title here ]
In [87]: bs.select('a #link1') #查找a标签中id为link1的
Out[87]: []
In [88]: bs.select('a #link1') #查找a标签中id为link1的
Out[88]: []
In [89]: bs.select('a[herf="http://www.baidu.com"]) #通过属性查找
File "" , line 1
bs.select('a[herf="http://www.baidu.com"]) #通过属性查找
^
SyntaxError: EOL while scanning string literal
In [90]: bs.select('a[herf="http://www.baidu.com"]') #通过属性查找
Out[90]: []
In [91]: bs.select('a[href="http://www.baidu.com"]') #通过属性查找
Out[91]: ["hehe" href="http://www.baidu.com" id="link1">-- hehehe -->]
In [92]: # 以上的 select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容
这个案例登录知乎,并把主页保存html。
关于验证码,有一种是字母数字,是将图片保存到本地,手动输入的,比如:jk12,请看注释掉的代码。另一种是点击倒立的文字,也是保存到本地的,手动输入坐标,坐标是有规律的,详细请看代码注释,如果第一个第二个是倒立的请输入:2,23,46
下面案例如果测试的话有三处需要改的地方:你的账号、你的密码、你的主页。
当然可以选择把55-57行代码注释掉。
1 # coding:utf-8
2
3 from bs4 import BeautifulSoup
4 import requests
5 import time
6
7 def captcha(captcha_data):
8 with open("captcha.jpg","wb") as f:
9 f.write(captcha_data)
10 '''
11 text=raw_input("请输入验证码:")
12 return text
13 '''
14 text=raw_input("请输入验证码个数以及坐标:")
15 # 第一个坐标[23,23],第二个坐标[46,23]...
16 arr=text.split(",")
17 if "1"==arr[0]:
18 result='{"img_size":[200,44],"input_points":[[%s,23]]}' % int(arr[1])
19 else:
20 result='{"img_size":[200,44],"input_points":[[%s,23],[%s,23]]}' % (int(arr[1]),int(arr[2]))
21
22 return result
23
24 def zhihuLogin():
25 # 构建一个Session对象,可以保存Cookie
26 session=requests.Session()
27
29 # get请求获取登录页面,找到需要的数据_xsrf,同时记录Cookie
30 html=session.get("https://www.zhihu.com/#signin",headers=headers).text
31
32 # 调用lxml解析库
33 bs=BeautifulSoup(html,"lxml");
34 # _xsrf作用是防止CSRF攻击(跨站请求伪造,也就是跨域攻击)
35 # 跨域攻击通常通过利用Cookie伪装成网站信任的用户的请求,盗取用户信息、欺骗web服务器
36 # 所以网站通过设置一个隐藏字段存放这个MD5字符串,用来校验用户Cookie和服务器Session
37 _xsrf=bs.find("input",attrs={"name":"_xsrf"}).get("value")
38
39 #captcha_url="http://www.zhihu.com/captcha.gif?r=%d&type=login"%(time.time()*1000)
40 captcha_url="https://www.zhihu.com/captcha.gif?r=%d&type=login&lang=cn"%(time.time()*1000)
41 captcha_data=session.get(captcha_url,headers=headers).content
42 text=captcha(captcha_data)
43
44 data={
45 "_xsrf":_xsrf,
46 "phone_num":"**你的账号**",
47 "password":"**你的密码**",
48 "captcha_type":"cn",
49 "captcha":text
50 }
51
52 response=session.post("https://www.zhihu.com/login/phone_num",data=data,headers=headers)
53 print response.text
54
55 response=session.get("**你登录后的主页地址**",headers=headers)
56 with open("my.html","w") as f:
57 f.write(response.text.encode("utf-8"))
58
59 if __name__=="__main__":
60 zhihuLogin()