之前写过一篇简单使用request的文章,这篇来写一些更有实用性一些的功能案例,需要结合使用re,bs4, xpath等。另外,上一篇仅仅是获取网页本身,而不涉及到媒体文件,比如图片,音频等等。
先来看看获取图片:
import urllib
url = 'http://duanziwang.com/usr/uploads/2019/02/3334500855.jpg'
urllib.request.urlretrieve(url=url,filename='./1.jpg')
urllib是requests是的早期版本,封装度相对更低一些,下载图片有urlretrieve方法:它有两个参数,第一个为图片的url,第二个为保存本地的文件名
再来看看通过requests实现
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
url = 'http://duanziwang.com/usr/uploads/2019/02/3334500855.jpg'
pic_data = requests.get(url=url,headers=headers).content #content返回的是二进制类型的响应数据
with open('2.jpg','wb') as fp:
fp.write(pic_data)
可以看到,获取图片是content属性,而非text
但也可以看到,urllib是直接获取,没有headers等参数,也就是没法进行伪装
re
分析网页源码:
<div class="post-content">
<p><img src="http://duanziwang.com/usr/uploads/2019/02/3334500855.jpg" alt="产品经理视角 vs 用户视角" title="产品经理视角 vs 用户视角"></p> </div>
案例, 下载段子网搞笑图片页的图片:
所有图片都在post-content对应的div中
import re
import os
import urllib
url = 'http://duanziwang.com/category/搞笑图/'
page_text = requests.get(url,headers=headers).text #页面源码数据
#新建一个文件夹
dirName = 'imgs'
if not os.path.exists(dirName):
os.mkdir(dirName)
#数据解析:每一张图片的地址
pattern = '<div class="post-content">.*?<img src="(.*?)" alt=.*?</div>'
img_src_list = re.findall(pattern,page_text,re.S) #因为存在换行,爬虫中使用findall函数必须要使用re.S
for src in img_src_list:
imgName = src.split('/')[-1]
imgPath = dirName+'/'+imgName
urllib.request.urlretrieve(url=src,filename=imgPath)
print(imgName,'下载成功!!!')
注意,这里用到了re.findall中的flag参数:
flag主要有以下取值:
- re.I 忽略大小写
- re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
- re.M 多行模式
- re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
- re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
- re.X 为了增加可读性,忽略空格和 # 后面的注释
bs4
- 环境的安装:
- pip install bs4
- pip install lxml
- 解析原理
- 实例化一个BeautifulSoup的一个对象,把即将被解析的页面源码内容加载到该对象中
- 调用BeautifulSoup对象中相关的方法和属性进行标签定位和本文数据的提取
- BeautifulSoup对象的实例化的方式:
- BeautifulSoup(fp,'lxml'):将本地的文件内容加载到该对象中进行数据解析
- BeautifulSoup(page_text,'lxml'):将互联网上请求到的数据加载到该对象中进行数据解析
### 相关解析操作
- 标签定位:返回值一定是定位到的标签
- soup.tagName:定位到第一个出现的tagName标签.返回的是单数
- 属性定位:soup.find('tagName',attrName='value'),返回的是单数
- find_all('tagName',attrName='value')返回的是复数(列表)
- 选择器定位:select('选择器'),返回的也是一个列表
- 层级选择器:
- 大于号:表示一个层级
- 空格:标识多个层级
- 取文本
- string:只可以将标签中直系的文本取出
- text:可以将标签中所有的内容取出
- 取属性
- tag['attrName']
案例:爬取名著:《红楼梦》
http://www.shicimingju.com/book/hongloumeng.html
首先,分析下网页:章节名(目录)都在一个网页中, 有个div,book-mulu,然后ul,li里面即是章节链接 章节名。
<div class="book-mulu">
<ul>
<li><a href="/book/hongloumeng/1.html">第 一 回 甄士隐梦幻识通灵 贾雨村风尘怀闺秀</a></li>
import re
import os
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}
base_url = 'http://www.shicimingju.com'
category_url = 'http://www.shicimingju.com/book/hongloumeng.html'
category_html = requests.get(url=category_url, headers=headers).text
soup = BeautifulSoup(category_html, 'lxml')
a_list = soup.select('.book-mulu li a')
dir_name = '红楼梦'
if not os.path.exists(dir_name):
os.mkdir(dir_name)
for a in a_list:
detail_url = base_url + a['href'] # 拼接详情页url
name = a.text # 章节名
file_path = os.path.join(dir_name, name+'.txt') # 拼接文件名
detail_html = requests.get(detail_url, headers=headers).text # 获取详情页数据
detail_soup = BeautifulSoup(detail_html, 'lxml')
article = detail_soup.find('div', class_='card bookmark-list').text # 获取详情页文字内容
with open(file_path, 'w',encoding='utf-8') as fp:
fp.write(article)