安装依赖以及页面解析

99封情书 提交于 2020-02-01 01:12:09

Date: 2019-06-19

Author: Sun

本节要学习的库有:

网络库:requests

页面解析库:Beautiful Soup

1 Requests库

​ 虽然Python的标准库中 urllib 模块已经包含了平常我们使用的大多数功能,但是它的 API 使用起来让人感觉不太好,而 Requests 自称 “HTTP for Humans”,说明使用更简洁方便。

​ Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。Requests 的哲学是以 PEP 20 的习语为中心开发的,所以它比 urllib 更加 Pythoner。更重要的一点是它支持 Python3 哦!

​ Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用:)

​ Requests 继承了urllib的所有特性。Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的 URL 和 POST 数据自动编码

​ requests 的底层实现其实就是 urllib3

​ Requests的文档非常完备,中文文档也相当不错。Requests能完全满足当前网络的需求,支持Python 2.6—3.6

1.1 安装 Requests

pip install requests  

Requests官方文档:

http://docs.python-requests.org/zh_CN/latest/user/quickstart.html

http协议测试网站:

http://httpbin.org/

1.2 基本用法:

import requests

response = requests.get('http://www.baidu.com')
print(response.request.url) # 等同于response.url
print(response.status_code)
#请求头是请求头,响应头是响应头
print(response.headers['content-type'])    #不区分大小写
print(response.encoding)
print(response.text)       #获取文本,一般情况自动解码

1.3 请求方法

​ Requests的请求不再像urllib一样需要去构造各种Request,opener和handler,使用Requests构造的方法,并在其中传入需要的参数即可
每一个请求方法都有一个对应的API,比如GET请求就可以使用get()方法

​ POST请求就可以使用post()方法,并且将需要提交的数据传递给data参数即可

​ 设置访问超时,设置timeout参数即可

requests.get(‘http://github.com’,timeout=0.01)

具体用例说明

import requests
response = requests.get('https://httpbin.org/get')        #拉数据
response = requests.post('http://gttpbin.org/post',data={'key': 'value'})   #推数据

# - post请求四种传送正文方式:
#   - 请求正文是application/x-www-form-urlencoded
#   - 请求正文是multipart/form-data
#   - 请求正文是raw
#   - 请求正文是binary

response = requests.put('http://httpbin.org/put',data={'key':'value'})
response = requests.delete('http://httpbin.org/delete')
response = requests.head('http://httpbin.org/get')
response = requests.options('http://httpbin.org/get')

1.4 传递URL参数

(1)传递URL参数也不用再像urllib中那样需要去拼接URL,而是简单的构造一个字典,并在请求时将其传递给params参数

(2)有时候我们会遇到相同的url参数名,但又不同的值,而Python的字典又不支持键的重名,可以把键的值用列表表示

#传递URL参数也不用再像urllib中那样需要去拼接URL,而是简单的构造一个字典,并在请求时将其传递给params参数
import requests
params = {'key1':'value1','key2':'value2'}
response = requests.get('http://httpbin.org/get',params=params)
#有时候我们会遇到相同的url参数名,但又不同的值,而Python的字典又不支持键的重名,可以把键的值用列表表示
params = {'key1':'value1','key2':['value2','value3']}
response = requests.get('http://httpbin.org/get',params=params)
print(response.url)
print(response.content)
#http://httpbin.org/get?key1=value1&key2=value2&key2=value3

1.5 自定义Headers
如果想自定义请求的Headers,同样的将字典数据传递给headers参数
url = ‘http://api.github.com/some/endpoint
headers = {‘user-agent’:‘my-app/0.0.1’} #自定义headers
response = requests.get(url,headers=headers)

print(response.headers)

1.6 自定义cookies

Requests中自定义cookies也不用再去构造CookieJar对象,直接将字典递给cookies参数

url = ‘http://httpbin.org/cookies’
co = {‘cookies_are’:‘working’}
response = requests.get(url,cookies=co)
print(response.text)   #{“cookies”: {“cookies_are”: “working”}}

1.7 设置代理

#当我们需要使用代理时,同样构造代理字典,传递给proxies参数
import requests
proxies = {
'http':'http://10.10.1.10:3128',
'https':'https://10.10.1.10:1080'
}
requests.get('http://httpbin.org/ip',proxies=proxy)
print(response.text)

2 requests库使用案例

例子1: 采用requests实现百度搜索功能

# -*- coding: utf-8 -*-
__author__ = 'sun'
__date__ = '2019/6/19 14:47'
import requests

def getfromBaidu(key):
    #url = 'http://www.baidu.com.cn/s?wd=' + urllib.parse.quote(key) + '&pn='  # word为关键词,pn是分页。
    kv = {'wd': key}
    r = requests.get("http://www.baidu.com/s", params=kv)
    print(r.request.url)
    with open("baidu.html", "w", encoding='utf8')   as  f:
        f.write(r.text)

key = 'python'
getfromBaidu(key)

例子2:采用get和post方法

# -*- coding: utf-8 -*-  
__author__ = 'sun'
__date__ = '2019/6/19 下午9:32'

import requests 
import  json
r = requests.get(url='http://www.sina.com')  # 最基本的GET请求
print(r.status_code)  # 获取返回状态
r = requests.get(url='http://dict.baidu.com/s', params={'wd': 'python'})  # 带参数的GET请求
print(r.url)
print(r.text)  # 打印解码后的返回数据

print("#####################")
payload = (('key1', 'value1'), ('key1', 'value2'))
#urlencode
r = requests.post('http://httpbin.org/post', data=payload)

print("code: " + str(r.status_code) + ", text:" + r.text)

url = 'http://httpbin.org/post'
files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
r = requests.post(url, files=files) 
print(r.text)

2 BeautifulSoup

简介

Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。官方解释如下:

Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。

​ Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。

​ Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度。

安装

​ Beautiful Soup 3 目前已经停止开发,推荐在现在的项目中使用Beautiful Soup 4,不过它已经被移植到BS4了,也就是说导入时我们需要 import bs4

进入python虚拟化环境,安装lxml和bs4

​ pip install lxml

​ pip install bs4

使用方法

首先必须要导入 bs4 库

from bs4 import BeautifulSoup

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:

1. Tag
2. NavigableString
3. BeautifulSoup
4. Comment

语法:见附件《Beautiful Soup 4.2.0 文档 — Beautiful Soup.pdf》

例子分析

假设串为:

html_doc = """
<html>
<head>
    <title>The Dormouse's story</title>
</head>
<body>
<p class="title aq">
    <b>
        The Dormouse's story
    </b>
</p>
<p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> 
    and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.
</p>
<p class="story">...</p>
"""

生成soup对象:

soup = BeautifulSoup(html_doc, 'lxml')

(1) Tag

通俗点讲就是 HTML 中的一个个标签,例如

<title>The Dormouse's story</title>
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

上面的 title a 等等 HTML 标签加上里面包括的内容就是 Tag; 下面我们来感受一下怎样用 Beautiful Soup 来方便地获取 Tags

print(soup.title)
# <title>The Dormouse's story</title>

print(soup.head)
# <head><title>The Dormouse's story</title></head>

print(soup.a)
# <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>

print(soup.p)
# <p class="title" name="dromouse"><b>The Dormouse's story</b></p>

print type(soup.a)
#<class 'bs4.element.Tag'>

对于 Tag,它有两个重要的属性,是 name 和 attrs

print(soup.name)
print(soup.head.name)
# [document]
# head

print soup.p.attrs
#{'class': ['title'], 'name': 'dromouse'}

print soup.p['class']
#['title']

print soup.p.get('class')   #等价于上述的
#['title']

可以对这些属性和内容等等进行修改,例如

soup.p['class'] = "newClass"
print(soup.p)
# <p class="newClass" name="dromouse"><b>The Dormouse's story</b></p>

复杂点的操作

# 获取所有文字内容
print(soup.get_text())

# 输出第一个  a 标签的所有属性信息
print(soup.a.attrs)

for link in soup.find_all('a'):
    # 获取 link 的  href 属性内容
    print(link.get('href'))

# 对soup.p的子节点进行循环输出    
for child in soup.p.children:
    print(child)

# 正则匹配,名字中带有b的标签
for tag in soup.find_all(re.compile("b")):
    print(tag.name)

(2) NavigableString

既然我们已经得到了标签的内容,那么问题来了,我们要想获取标签内部的文字怎么办呢?很简单,用 .string 即可,例如

print(soup.p.string)
#The Dormouse's story

案例2:

新建文件test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
   <div class="aaa" id="xxx">
       <p>Hello <span>world</span></p>
   </div>
   <div class="bbb" s="sss">bbbb1</div>
   <div class="ccc">ccc</div>
   <div class="ddd">dddd</div>
   <div class="eeee">eeeee</div>
</body>
</html>

测试python文件如下:

from bs4 import BeautifulSoup
import re
# 1. 创建BeautifulSoup对象
with open("test.html") as f:
    html_doc = f.read()

soup = BeautifulSoup(html_doc, 'lxml')
# 2. 按Tag name 找网页元素
print(f"2.:{soup.title}")
print(f"2.:{soup.title.string}")
# 3. 使用get_text()获取文本
print(f"3.get_text():{soup.div.get_text()}")
# 4. 如何获取属性
print("4.", soup.div['class'])
print("4.get", soup.div.get("class"))
print("4.attrs:", soup.div.attrs)
# 5. find_all(self, name=None, attrs={}, recursive=True, text=None,
#                 limit=None, **kwargs):
# 1) 获取所有符合过滤条件的Tag
# 2) 过滤条件可以是多个条件,也可以是单个条件
# 3)过滤条件支持正则表达式
# 4) 参数说明
# -name- : Tag name, 默认值是None
# -attrs-:字典,字典里可以放tag的多个属性。
# - recursive-:是否递归,默认值是True。
# - text-:按tag里面的文本内容找,也支持正则表达式,默认值是None
# - limit-: 限制找的个数,默认值是None即不限制个数,如果想限制只找前2个的话,
#   设置limit = 2即可。
# -kwargs - : 接受关键参数,可以指定特定的参数。例如: id = '',class_ = ''

divs = soup.find_all("div")
for div in divs:
    print("type(div)", type(div))
    print(div.get_text())
print(soup.find_all(name='div', class_='bbb'))
print("==", soup.find_all(limit=1, attrs={"class": re.compile('^b')}))
print(soup.find_all(text="bbbb1"))
print(soup.find_all(id="xxxx"))
# 6.find  limit =1 的find_all()
# 7.我们可以像使用find_all一样使用tag.( 按tagname找其实就是find_all的一个快捷方式)
soup.find_all(name='div', class_='bbb')
soup.div(class_='bbb')
# 注意:我们对Tag和BeautifulSoup类型的对象同等对待。
# 8. 查找当前Tag的子节点
# 1) 分多次查找
div_tag = soup.div
print(type(soup))
print(type(div_tag))
print(div_tag.p)
# 2)使用contents获得tag对象的子节点
print("8.2):", soup.div.contents)
# 9. children  返回  list_iterator 类型的对象
body_children = soup.body.children
for child in body_children:
    print("9. ", child)
# 10. 父节点
tag_p = soup.p
print("10.", tag_p.parent)

# 11. 兄弟节点find_next_siblings
# 找当前tag的下面的所有兄弟节点
div_ccc = soup.find(name='div',class_='ccc')
print("11.", div_ccc)
print("11.", div_ccc.find_next_siblings(name='div'))
# 12. 兄弟节点find_previous_siblings
print("12.", div_ccc.find_previous_siblings(name='div'))

soup.find_previous_sibling()

作业:
采用requests库爬取百度搜索页面,输入关键字,采用多线程或者多进程方式进行多页爬取

https://www.baidu.com/s?wd=python&pn=20

分页(页数为10页)爬取

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!