文章目录
一、Python爬虫必备两大模块
1.1 requests模块用于发送http请求
模块介绍
requests是使用Apache2 licensed 许可证的HTTP库,使用python编写,比urllib2模块更简洁。
Request支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动响应内容的编码,支持国际化的URL和POST数据自动编码。
在python内置模块的基础上进行了高度的封装,从而使得python进行网络请求时,变得人性化,使用Requests可以轻而易举的完成浏览器可有的任何操作。
此外,requests会自动实现持久连接keep-alive
快速上手
-
导入模块
import requests
-
发送请求
import requests r = requests.get('https://www.baidu.com') # 最基本的不带参数的get请求 r1 = requests.get(url='https://www.baidu.com', params={'wd': 'python的requests模块'}) # 带参数的get请求
注意:可以使用不同的方法发送不同类型的请求:
requests.get(‘https://www.baidu.com’) # GET请求 requests.post(“https://www.baidu.com”) # POST请求 requests.put(“https://www.baidu.com”) # PUT请求 requests.delete(“https://www.baidu.com”) # DELETE请求 requests.head(“https://www.baidu.com”) # HEAD请求 requests.options(“https://www.baidu.com” ) # OPTIONS请求
-
为url传递参数
url_params = {'key':'value'} # 字典传递参数,如果值为None的键不会被添加到url中 r = requests.get('your url',params = url_params) print(r.url)
-
响应的内容
# 属性: r.encoding # 获取当前的编码 r.encoding = 'utf-8' # 设置编码 r.text # 以encoding解析返回内容。字符串方式的响应体,会自动根据响应头部的字符编码进行解码。 r.content # 以字节形式(二进制)返回。字节方式的响应体,会自动为你解码 gzip 和 deflate 压缩。 r.headers # 以字典对象存储服务器响应头,但是这个字典比较特殊,字典键不区分大小写,若键不存在则返回None r.status_code # 响应状态码 r.raw # 返回原始响应体,也就是 urllib 的 response 对象,使用 r.raw.read() r.ok # 查看r.ok的布尔值便可以知道是否登陆成功 r.history # 返回重定向信息,当然可以在请求时加上allow_redirects = false 阻止重定向 r.requests.headers # 返回发送到服务器的头信息 # 方法: r.json() # Requests中内置的JSON解码器,以json形式返回,前提返回的内容确保是json格式的,不然解析出错会抛异常 r.raise_for_status() # 失败请求(非200响应)抛出异常
-
定制头和cookie信息
header = {'user-agent': 'my-app/0.0.1''} cookie = {'key':'value'} r = requests.get/post('your url',headers=header,cookies=cookie) data = {'some': 'data'} headers = {'content-type': 'application/json', 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0'} r = requests.post('https://api.github.com/some/endpoint', data=data, headers=headers) print(r.text)
-
设置请求超时
r = requests.get('url',timeout=1) # 设置秒数超时,仅对于连接有效
-
Session对象,能够跨请求保持某些参数
s = requests.Session() s.auth = ('auth','passwd') s.headers = {'key':'value'} r = s.get('url')
-
代理
proxies = {'http':'ip1','https':'ip2'} requests.get('url',proxies=proxies)
1.2 bs4(beautifulsoup)模块用于解析html文本
模块介绍
Beautiful Soup是python的一个HTML或XML的解析库,我们可以用它来方便的从网页中提取数据,它拥有强大的API和多样的解析方式
Beautiful Soup的三个特点:
- Beautiful Soup提供一些简单的函数,用于浏览、搜索和修改解析DOM树,它是一个工具箱,通过解析文档为用户提供需要抓取的数据
- Beautiful Soup自动将转入文档转换为Unicode编码,输出文档转换为UTF-8编码,不需要考虑编码,除非文档没有指定编码方式,这时只需要指定原始编码即可
- Beautiful Soup位于流行的Python解析器(如lxml和html5lib)之上,可以尝试不同的解析策略或交易速度以获得灵活性
快速上手
-
结点选择器:
直接调用节点的名称就可以选择节点元素,节点可以嵌套选择返回的类型都是bs4.element.Tag对象
soup=BeautifulSoup(html_doc,'lxml') print(soup.head) #获取head标签 print(soup.p.b) #获取p节点下的b节点 print(soup.a.string) #获取a标签下的文本,只获取第一个
name属性获取节点名称:
soup.body.name
attrs属性获取节点属性,也可以字典的形式直接获取,返回的结果可能是列表或字符串类型,取决于节点类型
soup.p.attrs #获取p节点所有属性 soup.p.attrs['class'] #获取p节点class属性 soup.p['class'] #直接获取p节点class属性
string属性获取节点元素包含的文本内容:
soup.p.string #获取第一个p节点下的文本内容
contents属性获取节点的直接子节点,以列表的形式返回内容
soup.body.contents #是直接子节点,不包括子孙节点
children属性获取的也是节点的直接子节点,只是以生成器的类型返回
soup.body.children
descendants属性获取子孙节点,返回生成器
soup.body.descendants
parent属性获取父节点,parents获取祖先节点,返回生成器
soup.b.parent soup.b.parents
next_sibling属性返回下一个兄弟节点,previous_sibling返回上一个兄弟节点,注意换行符也是一个节点,所以有时候在获取兄弟节点是通常是字符串或者空白
soup.a.next_sibling soup.a.previous_sibling
next_siblings和previous_sibling分别返回前面和后面的所有兄弟节点,返回生成器
soup.a.next_siblings soup.a.previous_siblings
next_element和previous_element属性获取下一个被解析的对象,或者上一个
soup.a.next_element soup.a.previous_element
next_elements和previous_elements迭代器向前或者后访问文档解析内容
soup.a.next_elements soup.a.previous_elements
-
方法选择器
前面使用的都是通过节点属性来选择的,这种方法非常快,但在进行比较复杂的选择时就不够灵活,幸好Beautiful Soup还为我们提供了一些查询方法,如fang_all()和find()等find_all(name,attrs,recursive,text,**kwargs)
:查询所有符合条件的元素,其中的参数:-
name表示可以查找所有名字为name的标签(tag),也可以是过滤器,正则表达式,列表或者是True
-
attrs表示传入的属性,可以通过attrs参数以字典的形式指定如常用属性id,attrs={‘id’:‘123’},由于class属性是python中的关键字,所有在查询时需要在class后面加上下划线即class_=‘element’,返回的结果是tag类型的列表
-
text参数用来匹配节点的文本,传入的形式可以是字符串也可以是正则表达式对象
-
recursive表示,如果只想搜索直接子节点可以将参数设为false:recursive=Flase
-
limit参数,可以用来限制返回结果的数量,与SQL中的limit关键字类似
find( name , attrs , recursive , text , **kwargs)
:它返回的是单个元素,也就是第一个匹配的元素,类型依然是tag类型,参数同find_all()一样另外还有许多查询方法,其用法和前面介绍的find_all()方法完全相同,只不过查询范围不同,参数也一样
-
find_parents(name , attrs , recursive , text , **kwargs)
和find_parent(name , attrs , recursive , text , **kwargs)
:前者返回所有祖先节点,后者返回直接父节点 -
find_next_siblings(name , attrs , recursive , text , **kwargs)
和find_next_sibling(name , attrs , recursive , text , **kwargs)
:对当前tag后面的节点进行迭代,前者返回后面的所有兄弟节点,后者返回后面第一个兄弟节点 -
find_previous_siblings(name , attrs , recursive , text , **kwargs)
和find_previous_sibling(name , attrs , recursive , text , **kwargs)
:对当前tag前面的节点进行迭代,前者返回前面的所有兄弟节点,后者返回前面的第一个兄弟节点 -
find_all_next(name , attrs , recursive , text , **kwargs)和find_next(name , attrs , recursive , text , **kwargs)
:对当前tag之后的tag和字符串进行迭代,前者返回所有符合条件的节点,后者返回第一个符合条件的节点 -
find_all_previous()
和find_previous()
:对当前tag之前的tag和字符串进行迭代,前者返回节点后所有符合条件的节点,后者返回第一个符合条件的节点
-
-
CSS选择器
在 Tag 或 BeautifulSoup 对象的 .select()方法中传入字符串参数,即可使用CSS选择器的语法找到对应的tag。需要有一定的CSS基础,否则不太推荐使用 -
tag修改方法
Beautiful Soup可以实现改变tag标志的属性的值,添加或删除属性和内容Tag.append() 方法向tag中添加内容,类似Python的列表的 .append() 方法:
In [30]: soup.a Out[30]: <a href="http://www.baidu.com/">百度</a> In [31]: soup.a.append('一下') In [32]: soup.a Out[32]: <a href="http://www.baidu.com/">百度一下</a>
new_tag()方法用于创建一个tag标签:
In [33]: soup=BeautifulSoup('<b></b>','lxml') In [34]: new_tag=soup.new_tag('a',href="http://www.python.org") #创建tag,第一个参数必须为tag的名称 In [35]: soup.b.append(new_tag) #添加到b节点下 In [36]: new_tag.string='python' #为tag设置值 In [37]: soup.b Out[37]: <b><a href="http://www.python.org">python</a></b>
其他方法:
-
insert()
将元素插入到指定的位置 -
inert_before()
在当前tag或文本节点前插入内容 -
insert_after()
在当前tag或文本节点后插入内容 -
clear()
移除当前tag的内容 -
extract()
将当前tag移除文档数,并作为方法结果返回 -
prettify()
将Beautiful Soup的文档数格式化后以Unicode编码输出,tag节点也可以调用 -
get_text()
输出tag中包含的文本内容,包括子孙tag中的内容 -
soup.original_encoding
属性记录了自动识别的编码结果 -
from_encoding
表示参数在创建BeautifulSoup对象是可以用来指定编码,减少猜测编码的运行速度
-
二、Python爬虫项目演示
2.1 爬取红袖小说排行榜上的书籍图片
程序代码:
import requests
import bs4
# 1. 准备工作
headers = { # 设置请求头信息(User-Agent),此操作为必须,否则http请求可能返回400的状态码,是一种反爬机制
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36"
}
# 2. 发送get请求并拿到响应内容
response = requests.get('https://www.hongxiu.com/rank', headers=headers)
# 3. 通过BeautifulSoup开始解析网页内容,使用lxml解析速度最快
soup = bs4.BeautifulSoup(response.content, 'lxml')
# 3.1 爬取各大榜单对应的页面url
pages = [i.attrs['href'] for i in soup.select("div.rank-nav-list a")]
# print(pages) 查看爬到的信息,发现a标签里面存的是uri
page_urls = ['https://www.hongxiu.com' + i for i in pages[1:]] # 将uri加上域名变为url
# 3.2 去每个页面下爬取对应的书籍信息
for url in page_urls:
res = requests.get(url, headers=headers)
page_soup = bs4.BeautifulSoup(res.content, 'lxml')
# 拿到图片url
image_url = [i.attrs['src'] for i in page_soup.select("div.rank-body div.book-img-box img")]
# 拿到书籍名称,用来做图片名
image_name = [i.string for i in page_soup.select("h4 a")]
# 4. 下载爬到的图片
for i in range(len(image_url)):
download = requests.get('https:' + image_url[i], headers=headers)
print(image_name[i])
with open("./images/" + image_name[i] + ".jpg", "bw") as file:
file.write(download.content)
程序执行结果:
参考: