一、简介

1.下载:pip install lxml

推荐使用douban提供的pipy国内镜像服务,如果想手动指定源,可以在pip后面跟-i 来指定源,比如用豆瓣的源来安装web.py框架:

pip install web.py -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

2.导包

from lxml import etree

3.xpath解析原理:

  • 实例化一个etree对象,然后将即将被解析的页面源码数据加载到该对象中。
  • 通过调用etree对象中的xpath方法,结合着xpath表达式进行标签定位和数据提取

4.如何实例化一个etree对象:

  将html文档或者xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点

  • 本地文件:将本地的一个html文档中的数据加载到etree对象中, 使用的比较少
tree = etree.parse(文件名fileName)
tree.xpath("xpath表达式")
  • 网络数据:将互联网爬取到的页面源码数据加载到该对象中
tree = etree.HTML(网页内容字符串page_text)
tree.xpath("xpath表达式")

启动和关闭插件 ctrl + shift + x

二、常用xpath表达式

首先,本地新建一个html文档,所以要使用etree.parse(fileName)

<html lang="en">
<head>
<meta charset="UTF-8" />
<title>测试bs4</title>
</head>
<body>
<div>
<p>百里守约</p>
</div> <div class="song">
<p>李清照</p>
<p>王安石</p>
<p>苏轼</p>
<p>柳宗元</p>
<a href="http://www.song.com/" title="赵匡胤" target="_self">
<span>this is span</span>
宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
<a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
<img src="http://www.baidu.com/meinv.jpg" alt="" />
</div> <div class="tang">
<ul>
<li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
<li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
<li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
<li><a href="http://www.sina.com" class="du">杜甫</a></li>
<li><a href="http://www.dudu.com" class="du">杜牧</a></li>
<li><b>杜小月</b></li>
<li><i>度蜜月</i></li>
<li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
</ul>
</div>
</body></html>

页面显示如下

层级&索引定位

#找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
//div[@class="tang"]/ul/li[2]/a 下面这三个结果相同
r = tree.xpath('/html/head/title')
r = tree.xpath('/html//title')
r = tree.xpath('//title')

r = tree.xpath('//p')            # 所有的p标签

标签定位:

//div[@class="song"]     # 找到class属性值为song的div标签 

模糊匹配:

//div[contains(@class, "ng")]       # class属性值包含ng的div
//div[starts-with(@class, "ta")] # class属性以ta开头的div

取属性:

//div[@class="tang"]//li[2]/a/@href

r = tree.xpath('//div[@class="song"]/img/@src')
print(r)

取文本: /text()直系的文本内容  //text()所有的文本内容

//div[@class="song"]/p[1]/text()     # /表示获取某个标签下的文本内容
//div[@class="tang"]//text() # //表示获取某个标签下的文本内容和所有子标签下的文本内容
# 获得的是列表,只不过里面只有一个元素
r = tree.xpath('//div[@class="song"]/p[4]/text()')
print(r)

r = tree.xpath('//div[@class="song"]/p[4]/text()')[0]
print(r)

r = tree.xpath('//div[@class="song"]//text()')
print(r)

逻辑运算

# 找到href属性值为空且class属性值为du的a标签
//a[@href="" and @class="du"]

三、案例

案例1:解析图片数据:http://pic.netbian.com/4kmeinv/

查看:网址鼠标悬浮上去会有图片名称,所以爬取图片以及对应的名称,要提前确定不是动态加载的。

import requests
from lxml import etree headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
url = 'http://pic.netbian.com/4kdongman/' response = requests.get(url=url,headers=headers)
# response.encoding = 'utf-8' #手动设定响应数据的编码 page_text = response.text #数据解析(图片地址,图片名称)
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="slist"]/ul/li') for li in li_list: #局部内容解析一定是以./开头。etree和element都可以调用xpath
img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0] # 解析出来的没有域名,要加上
img_name = li.xpath('./a/img/@alt')[0] #不要忘记前面加点号,表示从当前li标签开始
img_name = img_name.encode('iso-8859-1').decode('gbk') #处理中文乱码的通用形式
img_data = requests.get(url=img_src,headers=headers).content img_path = './qiutuLibs/'+img_name+'.jpg'
with open(img_path,'wb') as fp:
fp.write(img_data)
print(img_name,'下载成功!!!')

解析:
1.

li_list = tree.xpath('//div[@class="slist"]/ul/li')
print(li_list) # 返回的是一个element类型的数据对象

 2.

li标签里面有a标签,然后再里面是img标签, 然后有一个src属性和alt属性

img_src = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]                    # 解析出来的没有域名,要加上
img_name = li.xpath('./a/img/@alt')[0]

3. 出现乱码,有两种解决策略:

(1)对整体设定响应数据的编码

手动设定响应数据的编码,查看页面是用哪种编码方式是utf-8,还是gbk等。如果这种方式不行,用下面的方式

response.encoding = 'utf-8'

(2)针对具体的内容手动设定

img_name = img_name.encode('iso-8859-1').decode('gbk')     #处理中文乱码的通用形式

案例2:xpath解析-boss直聘

import requests
from lxml import etree
import json headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
} url = 'https://www.zhipin.com/job_detail/?query=python%E7%88%AC%E8%99%AB&city=101010100&industry=&position='
page_text = requests.get(url=url, headers=headers).text # 数据解析:jobName,salary,company,jobDesc
tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="job-list"]/ul/li')
job_data_list = []
for li in li_list:
job_name = li.xpath('.//div[@class="info-primary"]/h3/a/div/text()')[0] # 记得后面加[0]
salary = li.xpath('.//div[@class="info-primary"]/h3/a/span/text()')[0]
company = li.xpath('.//div[@class="company-text"]/h3/a/text()')[0]
detail_url = 'https://www.zhipin.com' + li.xpath('.//div[@class="info-primary"]/h3/a/@href')[0] # 详情页的页面源码数据
detail_page_text = requests.get(url=detail_url, headers=headers).text
detail_tree = etree.HTML(detail_page_text)
job_desc = detail_tree.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div//text()')
job_desc = ''.join(job_desc) dic = {
'job_name': job_name,
'salary': salary,
'company': company,
'job_desc': job_desc
}
job_data_list.append(dic) fp = open('job.json', 'w', encoding='utf-8')
json.dump(job_data_list, fp, ensure_ascii=False)
fp.close()
print('over')

解析:

1. 因为有br标签,所以用//

job_desc = detail_tree.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div//text()')
print(job_desc)

2. 输出的是列表,里面是元素

所以,字符串拼接

job_desc = detail_tree.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div//text()')
job_desc = ''.join(job_desc)
print(job_desc)

最终文件

案例3:xpath解析-热门城市全国城市名称  https://www.aqistudy.cn/historydata

import requests
from lxml import etree
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url,headers=headers).text tree = etree.HTML(page_text)
city_list = tree.xpath('//div[@class="bottom"]/ul/li/a/text() | //div[@class="bottom"]/ul/div[2]/li/a/text()') # 逻辑 #hot_city://div[@class="bottom"]/ul/li/a/text()
#all_city://div[@class="bottom"]/ul/div[2]/li/a/text()
print(city_list)
print(len(city_list))

全部城市: //div[@class="bottom"]/ul/div[2]/li/a/text()

案例4:获取好段子中段子的内容和作者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
tree=etree.HTML(url_content) # 使用xpath解析从网络上获取的数据
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:
text_list=ele.xpath('./div[@class="cont"]//text()') # 段子的文本内容(是存放在list列表中)
text_str=str(text_list) # list列表中的文本内容全部提取到一个字符串中
text_list.append(text_str) # 字符串形式的文本内容防止到all_text列表中 print(title_list)
print(text_list)

案例5:58二手房

import requests
from lxml import etree
url ='https://bj.58.com/shahe/ershoufang/?utm_source=market&spm=u-2d2yxv86y3v43nkddh1.BDPCPZ_BT&PGTID=0d30000c-0047-e4e6-f587-683307ca570e&ClickID=1'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
page_text = requests.get(url=url,headers=headers).text tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')
fp = open('58.csv','w',encoding='utf-8')
for li in li_list:
title = li.xpath('./div[2]/h2/a/text()')[0]
price = li.xpath('./div[3]//text()')
price = ''.join(price)
fp.write(title+":"+price+'\n')
fp.close()
print('over')

案例6:http://pic.netbian.com/4kmeinv/

import requests
from lxml import etree
import os
import urllib url = 'http://pic.netbian.com/4kmeinv/'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
response = requests.get(url=url,headers=headers)
#response.encoding = 'utf-8'
if not os.path.exists('./imgs'):
os.mkdir('./imgs'
)
page_text = response.text tree = etree.HTML(page_text)
li_list = tree.xpath('//div[@class="slist"]/ul/li')
for li in li_list:
img_name = li.xpath('./a/b/text()')[0]
#处理中文乱码
img_name = img_name.encode('iso-8859-1').decode('gbk')
img_url = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
img_path = './imgs/'+img_name+'.jpg'
urllib.request.urlretrieve
(url=img_url,filename=img_path)
print(img_path,'下载成功!')
print('over!!!')

案例7下载煎蛋网中的图片数据:http://jandan.net/ooxx【重点】src加密*****

import requests
from lxml import etree
from fake_useragent import UserAgent
import base64
import urllib.request url = 'http://jandan.net/ooxx'
ua = UserAgent(verify_ssl=False,use_cache_server=False).random
headers = {
'User-Agent':ua
}
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text) #在抓包工具的数据包响应对象对应的页面中进行xpath的编写,而不是在浏览器页面中。
#获取了加密的图片url数据
imgCode_list = tree.xpath('//span[@class="img-hash"]/text()') imgUrl_list = []
for url in imgCode_list:
img_url = 'http:'+base64.b64decode(url).decode() #base64.b64decode(url)为byte类型,需要转成str
imgUrl_list.append(img_url) for url in imgUrl_list:
filePath = url.split('/')[-1]
urllib.request.urlretrieve(url=url,filename=filePath)
print(filePath+'下载成功')

查看页面源码:发现所有图片的src值都是一样的。简单观察会发现每张图片加载都是通过jandan_load_img(this)这个js函数实现的。在该函数后面还有一个class值为img-hash的标签,里面存储的是一组hash值,该值就是加密后的img地址加密就是通过js函数实现的,所以分析js函数,获知加密方式,然后进行解密。

通过抓包工具抓取起始url的数据包,在数据包中全局搜索js函数名(jandan_load_img),然后分析该函数实现加密的方式。在该js函数中发现有一个方法调用,该方法就是加密方式,对该方法进行搜索搜索到的方法中会发现base64和md5等字样,md5是不可逆的所以优先考虑使用base64解密

 

案例7爬取站长素材中的简历模板

import requests
import random
from lxml import etree
headers = {
'Connection':'close', # 当请求成功后,马上断开该次请求(及时释放请求池中的资源)
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36'
}
url = 'http://sc.chinaz.com/jianli/free_%d.html'
for page in range(1,4): # 因为第一页和其他页url格式不一样,所以分情况讨论
if page == 1:
new_url = 'http://sc.chinaz.com/jianli/free.html'
else:
new_url = format(url%page) response = requests.get(url=new_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:
detail_url = div.xpath('./a/@href')[0]
name = div.xpath('./a/img/@alt')[0] detail_page = requests.get(url=detail_url,headers=headers).text
tree = etree.HTML(detail_page)
download_list = tree.xpath('//div[@class="clearfix mt20 downlist"]/ul/li/a/@href') # 这样获得的是每个的所有下载链接
download_url = random.choice(download_list) # 为了防止每个链接因请求过于频繁被禁,随机选择一个
data = requests.get(url=download_url,headers=headers).content
fileName = name+'.rar'
with open(fileName,'wb') as fp:
fp.write(data)
print(fileName,'下载成功')

Alt里面的图片名称是中文,要注意打印看一下会不会有乱码

 

有乱码,尝试用第一种方式是否可以解决,可以解决就不用第二种方式

详情页中每个li标签对应一个下载地址

li标签里有一个a

05 requests模块进阶的更多相关文章

  1. 爬虫中之Requests 模块的进阶

    requests进阶内容 session处理cookie proxies参数设置请求代理ip 基于线程池的数据爬取 引入 有些时候,我们在使用爬虫程序去爬取一些用户相关信息的数据(爬取张三“人人网”个 ...

  2. 爬虫基础之requests模块

    1. 爬虫简介 1.1 概述 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本. 1.2 爬虫的价值 在互 ...

  3. 洗礼灵魂,修炼python(61)--爬虫篇—【转载】requests模块

    requests 1.简介 Requests 是用Python语言编写的第三方库,所以你需要pip安装,安装过程就略过了.它基于urllib,采用 Apache2 Licensed 开源协议的 HTT ...

  4. 2 爬虫 requests模块

    requests模块 Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库,Requests它会比urllib更加方便,reques ...

  5. requests模块基础

    requests模块 .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { bor ...

  6. 爬虫requests模块 1

    让我们从一些简单的示例开始吧. 发送请求¶ 使用 Requests 发送网络请求非常简单. 一开始要导入 Requests 模块: >>> import requests 然后,尝试 ...

  7. requests 模块

    发送请求 使用Requests发送网络请求非常简单. 一开始要导入Requests模块: >>> import requests 然后,尝试获取某个网页.本例子中,我们来获取Gith ...

  8. requests模块--python发送http请求

    requests模块 在Python内置模块(urllib.urllib2.httplib)的基础上进行了高度的封装,从而使得Pythoner更好的进行http请求,使用Requests可以轻而易举的 ...

  9. Python requests模块学习笔记

    目录 Requests模块说明 Requests模块安装 Requests模块简单入门 Requests示例 参考文档   1.Requests模块说明 Requests 是使用 Apache2 Li ...

随机推荐

  1. spring mvc 拦截器的使用

    Spring MVC 拦截器的使用 拦截器简介 Spring MVC 中的拦截器(Interceptor)类似于 Servler 中的过滤器(Filter).用于对处理器进行预处理和后处理.常用于日志 ...

  2. BAT的人都是怎么学习的

    不知道你发现没,在技术领域走在前列的人,基本都符合一个条件:保持对新技术的敏感度,还能定期更新自己的技能储备. 要做到这一点,最高效的办法就是直接跟 BAT 等一线大厂取经.说白了,平台足够大,就有更 ...

  3. 黑羽压测 比 jmeter、locust、loadrunner 更简便,性能更强

    视频讲解 点击下方链接,观看 讲解视频 https://www.bilibili.com/video/av60089015/ 动机 目前市场上对API接口做性能测试工具有 Jmeter.LoadRun ...

  4. markdown插入表格语法

    markdown插入表格语法 举例 如表格标题为,姓名,班级,成绩 标题内的内容为,yang,a班,100 我们要在markdow文件中插入表格 如 姓名|班级|成绩 -|-|- yang|a班|10 ...

  5. spring配置文件比较全的约束

    个人总结:Spring的配置文件applicationContext.xml约束文件.全面约束 <?xml version="1.0" encoding="utf- ...

  6. C#3.0新增功能09 LINQ 标准查询运算符 03 按执行方式的分类

    连载目录    [已更新最新开发文章,点击查看详细] 标准查询运算符方法的 LINQ to Objects 实现主要通过两种方法之一执行:立即执行和延迟执行.使用延迟执行的查询运算符可以进一步分为两种 ...

  7. C#2.0新增功能03 匿名方法

    连载目录    [已更新最新开发文章,点击查看详细] 在 2.0 之前的 C# 版本中,声明委托的唯一方式是使用命名方法. C# 2.0 引入匿名方法,在 C# 3.0 及更高版本中,Lambda 表 ...

  8. Java 集合框架部分面试题

    1.Java集合框架是什么?说出一些集合框架的优点? 每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector.Stack.HashTable和Array.随着集合的广泛使用,Java1 ...

  9. python load,loads,dumps,dump区别

    json 模块提供了一种很简单的方式来编码和解码JSON数据. 其中两个主要的函数是 json.dumps()和 json.loads() , 要比其他序列化函数库如pickle的接口少得多. 下面演 ...

  10. C语言编程入门之--第三章编写第一个C语言程序

    第三章 编写第一个C语言程序 导读:一般学一门计算机语言的第一堂上机课(“上机”顾名思义,上了计算机),就是往屏幕输出“hello world”,本章也不例外. 1.1 Hello,World! 这一 ...