BeautifulSoup4介绍与登录知乎案例

一 、BeautifulSoup4介绍
  • 和lxml一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据
  • lxml 只会局部遍历,而Beautiful Soup 是基于HTML DOM的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml
  • BeautifulSoup 用来解析 HTML 比较简单,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器
  • Beautiful Soup 3 目前已经停止开发,推荐现在的项目使用Beautiful Soup 4。使用 pip 安装即可:pip install beautifulsoup4
  • 官方文档:http://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/
  • -
二、使用

示例代码:

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")
1、四大对象种类,Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
  • tag 它查找的是在所有内容中的第一个符合要求的标签
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'}
  • NavigableString

In [45]: bs.title.string   #.string获取标签内容
Out[45]: u'Insert title here'

In [46]: print type(bs.title.string)
<class 'bs4.element.NavigableString'>
  • BeautifulSoup
In [38]: bs.name
Out[38]: u'[document]'

In [39]: print type(bs.name)
'unicode'>

In [40]: bs.attrs
Out[40]: {}

In [41]: # 文档本身属性为空
  • Comment 是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号
In [35]: bs.a.string #获取a标签内文字
Out[35]: u' hehehe '

In [36]: print type(bs.a.string)
<class 'bs4.element.Comment'>
2. 遍历文档树
  • 直接子节点: .contents .children 属性
    .content 属性可以将tag的子节点以列表的方式输出
    .children 返回的是一个生成器对象
In [52]: bs.frameset.contents
Out[52]: 
[u'\n',
 "1" noresize="noresize" src="04_table.html"/>,
 u'\n',
 "20%,*">\n"1" noresize="noresize" src="layout/b.html"/>\n"1" name="content" noresize="noresize"/>\n,
 u'\n']

In [53]: bs.frameset.contents[3]
Out[53]: "20%,*">\n"1" noresize="noresize" src="layout/b.html"/>\n"1" name="content" noresize="noresize"/>\n
  • 所有子孙节点: .descendants 属性 ,也需要遍历
  • 节点内容:.string属性
    如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点。如果一个tag仅有一个子节点,那么这个tag也可以使用 .string 方法,输出结果与当前唯一子节点的 .string 结果相同。

    通俗点说就是:如果一个标签里面没有标签了,那么 .string 就会返回标签里面的内容。如果标签里面只有唯一的一个标签了,那么 .string 也会返回最里面的内容

3、搜索文档树

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']
4、select方式
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()

你可能感兴趣的:(Python学习笔记)