- 常用xpath表达式回顾
属性定位:
#找到class属性值为song的div标签
//div[@class="song"]
层级&索引定位:
#找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
//div[@class="tang"]/ul/li[2]/a
逻辑运算:
#找到href属性值为空且class属性值为du的a标签
//a[@href="" and @class="du"]
模糊匹配:
//div[contains(@class, "ng")]
//div[starts-with(@class, "ta")]
取文本:
# /表示获取某个标签下的文本内容
# //表示获取某个标签下的文本内容和所有子标签下的文本内容
//div[@class="song"]/p[1]/text()
//div[@class="tang"]//text()
取属性:
//div[@class="tang"]//li[2]/a/@href
- 代码中使用xpath表达式进行数据解析:
1.下载:pip install lxml
2.导包:from lxml import etree
3.将html文档或者xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点
2.1 本地文件:tree = etree.parse(文件名)
tree.xpath("xpath表达式")
2.2 网络数据:tree = etree.HTML(网页内容字符串)
tree.xpath("xpath表达式")
- 安装xpath插件在浏览器中对xpath表达式进行验证:可以在插件中直接执行xpath表达式
-
将xpath插件拖动到谷歌浏览器拓展程序(更多工具)中,安装成功
-
启动和关闭插件 ctrl + shift + x
-
-
项目需求:获取好段子中段子的内容和作者 http://www.haoduanzi.com
from lxml import etree import requests url='http://www.haoduanzi.com/category-10_2.html' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36', } url_content=requests.get(url,headers=headers).text #使用xpath对url_conten进行解析 #使用xpath解析从网络上获取的数据 tree=etree.HTML(url_content) #解析获取当页所有段子的标题 title_list=tree.xpath('//div[@class="log cate10 auth1"]/h3/a/text()') ele_div_list=tree.xpath('//div[@class="log cate10 auth1"]') text_list=[] #最终会存储12个段子的文本内容 for ele in ele_div_list: #段子的文本内容(是存放在list列表中) text_list=ele.xpath('./div[@class="cont"]//text()') #list列表中的文本内容全部提取到一个字符串中 text_str=str(text_list) #字符串形式的文本内容防止到all_text列表中 text_list.append(text_str) print(title_list) print(text_list)
用xpath爬取小说《三国演义》实例:
1 from lxml import etree 2 import requests 3 4 url = 'http://www.shicimingju.com/book/sanguoyanyi.html' 5 headers = { 6 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", 7 "Connection":"close" 8 } 9 url_content = requests.get(url=url,headers=headers).text 10 11 tree = etree.HTML(url_content) 12 href_list = tree.xpath('//div[@class="book-mulu"]//li/a/@href') 13 new_url = 'http://www.shicimingju.com' 14 print("开始") 15 with open('./sanguo_xpath.txt','w',encoding='utf-8') as fp: 16 for href in href_list: 17 zhangjie_url = new_url + href 18 url_zhangjie = requests.get(url=zhangjie_url,headers=headers).text 19 zhangjie_tree = etree.HTML(url_zhangjie) 20 content_title = zhangjie_tree.xpath('//div[@class="www-main-container www-shadow-card "]/h1/text()')[0] 21 content = "".join(zhangjie_tree.xpath('//div[@class="chapter_content"]//text()')) 22 fp.write(content_title+" "+content+" ") 23 print("结束")
【重点】
- 问题:往往在进行大量请求发送的时候,经常会报出这一样的一个错误:HTTPConnectionPool(host:XX)Max retries exceeded with url。
- 原因:
1.每次数据传输前客户端要和服务器建立TCP连接,为节省传输消耗,默认为keep-alive,即连接一次,传输多次。然而如果连接迟迟不断开的话,则连接池满后则无法产生新的链接对象,导致请求无法发送。
2.ip被封
3.请求频率太频繁
- 解决:如果下列解决未生效,则可以尝试再次执行程序
1.设置请求头中的Connection的值为close,表示每次请求成功后断开连接
2.更换请求ip
3.每次请求之间使用sleep进行等待间隔
import requests
from fake_useragent import UserAgent
from lxml import etree
import random
import time
url = 'http://sc.chinaz.com/jianli/free_%d.html'
ua = UserAgent(verify_ssl=False,use_cache_server=False).random
headers = {
'User-Agent':ua,
#保证http请求成功后,立即断开连接,以解决HTTPConnectionPool(host:XX)Max retries exceeded with url的问题
'Connection': 'close', #该行不写,则会报错
}
#proxy_list = ['101.255.56.201:36501','39.137.69.10:8080','195.29.106.178:58292','120.76.77.152:9999','178.75.1.111:50411','78.156.225.170:41258','193.192.177.196:56480']
for pageNum in range(1,3):
get_url = format(url%pageNum)
if pageNum==1:
get_url = 'http://sc.chinaz.com/jianli/free.html'
response = requests.get(url=get_url,headers=headers)
response.encoding = 'utf-8'#处理中文乱码问题
page_text = response.text
tree = etree.HTML(page_text)
div_list = tree.xpath('//div[@id="container"]/div')
for div in div_list:
second_url = div.xpath('./a/@href')[0]
name = div.xpath('./p/a/text()')[0]+'.rar'
second_page_text = requests.get(url=second_url,headers=headers).text
second_tree = etree.HTML(second_page_text)
download_url_list = second_tree.xpath('//div[@class="clearfix mt20 downlist"]/ul/li/a/@href')
download_url = random.choice(download_url_list)
data = requests.get(url=download_url,headers=headers).content
with open(name,'wb') as fp:
fp.write(data)
print('下载完毕===>'+name)
#解决HTTPConnectionPool(host:XX)Max retries exceeded with url的问题:
#time.sleep(3) #延长请求时间,模拟浏览器,否则请求频率太快会请求失败
#使用代理池
#设置请求头信息中的Connection为close
.BeautifulSoup解析
- 环境安装
- 需要将pip源设置为国内源,阿里源、豆瓣源、网易源等
- windows
(1)打开文件资源管理器(文件夹地址栏中)
(2)地址栏上面输入 %appdata%
(3)在这里面新建一个文件夹 pip
(4)在pip文件夹里面新建一个文件叫做 pip.ini ,内容写如下即可
[global]
timeout = 6000
index-url = https://mirrors.aliyun.com/pypi/simple/
trusted-host = mirrors.aliyun.com
- linux
(1)cd ~
(2)mkdir ~/.pip
(3)vi ~/.pip/pip.conf
(4)编辑内容,和windows一模一样
- 需要安装:pip install bs4
bs4在使用时候需要一个第三方库,把这个库也安装一下
pip install lxml
- 基础使用
使用流程:
- 导包:from bs4 import BeautifulSoup
- 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的节点内容
(1)转化本地文件:
- soup = BeautifulSoup(open('本地文件'), 'lxml')
(2)转化网络文件:
- soup = BeautifulSoup('字符串类型或者字节类型', 'lxml')
(3)打印soup对象显示内容为html文件中的内容
基础巩固:
(1)根据标签名查找
- soup.a 只能找到第一个符合要求的标签
(2)获取属性
- soup.a.attrs 获取a所有的属性和属性值,返回一个字典
- soup.a.attrs['href'] 获取href属性
- soup.a['href'] 也可简写为这种形式
(3)获取内容
- soup.a.string
- soup.a.text
- soup.a.get_text()
【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
(4)find:找到第一个符合要求的标签
- soup.find('a') 找到第一个符合要求的
- soup.find('a', title="xxx")
- soup.find('a', alt="xxx")
- soup.find('a', class_="xxx")
- soup.find('a', id="xxx")
(5)find_all:找到所有符合要求的标签
- soup.find_all('a')
- soup.find_all(['a','b']) 找到所有的a和b标签
- soup.find_all('a', limit=2) 限制前两个
(6)根据选择器选择指定的内容
select:soup.select('#feng')
- 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
- 层级选择器:
div .dudu #lala .meme .xixi 下面好多级
div > p > a > .lala 只能是下面一级
【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
用bs4爬取《三国演义》代码:
1 from bs4 import BeautifulSoup 2 import requests 3 4 headers = { 5 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36", 6 "Connection":"close" 7 } 8 url = "http://www.shicimingju.com/book/sanguoyanyi.html" 9 10 def get_content(content_url): 11 new_url= "http://www.shicimingju.com" 12 get_cont_url = new_url + content_url 13 print(get_cont_url) 14 res = requests.get(url=get_cont_url,headers=headers).text 15 new_bs4_obj = BeautifulSoup(res,'lxml') 16 ele = new_bs4_obj.find('div',class_='chapter_content') 17 content = ele.text 18 return content 19 20 response = requests.get(url=url, headers=headers) 21 res_text = response.text 22 bs4_obj = BeautifulSoup(res_text,'lxml') 23 a_elements = bs4_obj.select('.book-mulu > ul > li > a') 24 print(a_elements) 25 with open('./sanguo_bs4.txt','w',encoding='utf-8') as fp: 26 print("开始") 27 for a_element in a_elements: 28 title = a_element.text 29 content_url = a_element['href'] 30 print(title) 31 print(content_url) 32 content = get_content(content_url) 33 fp.write(title + " " + content +" ") 34 print("结束")