13天搞定Python分布爬虫(第三天)(主要讲解对请求的数据进行提取的各种方式)
第三天
15-re的使用
import re s = '<div><a href="http://sogo.com">搜狗sogo</a></div>' result = re.findall(r'">(.+?)</', s) # 加?表示非贪婪模式,否则结果为['搜狗sogo</a>'] print(result) # ['搜狗sogo'] result = re.sub(r'<div>(.+)</div', r'<span>\1</span>', s) print(result) # <span><a href="http://sogo.com">搜狗sogo</a></span>>
16-糗事百科案例
debug调试技能
import requests, re from fake_useragent import UserAgent url = 'http://qiushibaike.com' headers = { 'User-Agent': UserAgent().random } resp = requests.get(url, headers=headers) info = resp.text # print(info) results = re.findall(r'<div class="content">\s*<span>\s*(.+)\s*</span>', info) with open('段子.txt', 'w', encoding='utf-8') as f: for i in results: f.write(i + '\n\n')
17-BeautifulSoup的使用
1 BeautifulSoup简介
BeautifulSoup提供一些简单的,Python式的函数用来处理导航、搜索,修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
BeautifulSoup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,BeautifulSoup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。
BeautifulSoup已成为和lxml、html6lib一样出色的python解析器,为用户灵活地提供不同的解析策略或强劲的速度
官网http://beautifulsoup.readthedocs.io/zh_CN/latest/
2 BeautifulSoup安装
BeautifulSoup3目前已停止开发,推荐在现在项目中使用BeautifulSoup4,不过它已经被移植到BS4了,也就是说导入时我们需要import bs4
pip install beautifulsoup4或pip install bs4
BeautifulSoup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,如果我们不安装它,则Python会使用Python默认的解析器,lxml解析器更加强大,速度更快,推荐安装。
解析器 | 使用方法 | 优点 | 缺点 |
Python标准库 | BeautifulSoup(markup,"html.parser") |
1.Python的内置标准库 2.执行速度适中 3.文档容错能力强 |
Python2.7.3或3.2.2前的版本中文档容错能力差 |
lxml HTML解析器 | BeautifulSoup(markup,"lxml") |
1.速度快 2.文档容错能力强 |
需要安装C语言库 |
lxml XML解析器 |
BeautifulSoup(markup,["lxml","xml"]) BeautifulSoup(markup,"xml") |
1.速度快 2.唯一支持XML的解析器 3.需要安装语言库 |
|
html5lib | BeautifulSoup(markup,"html5lib") |
1.最好的容错性 2.以浏览器的方式解析文档 3.生成HTML5格式的文档 4.速度慢 |
不依赖外部扩展 |
3 创建BeautifulSoup对象
from bs4 import BeautifulSoup
bs = BeautifulSoup(html,'lxml')
4 四大对象
BeautifulSoup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
1)Tag 2)NavigableString 3)BeautifulSoup 4)Comment
4.1 Tag就是HTML中的标签,例<div>
使用方法:
<title>学习爬虫</title>
<div class='info' float='left'>欢迎</div>
<div class='info' float='right'>
<span>好好学习,天天向上</span>
<a href='http://sogo.com'></a>
<strong><!--这是注释--></strong>
</div>
4.1.1 获取标签
#以lxml方式解析
bs=BeautifulSoup(info,'lxml')
print(bs.title)
4.1.2 获取属性
#获取所有属性
print(bs.title.attrs)
#获取单个属性的值
print(bs.div.get('class'))
print(bs.div['class'])
print(bs.a['href'])
4.2 NavigableString获取内容
print(bs.title.string) #能获取到注释
print(bs.title.text) #不能获取到注释
4.3 BeautifulSoup
BeautifulSoup对象表示的是一个文档的全部内容,大部分时候,可以把它当作Tag对象,它支持遍历文档树和搜索文档树中描述的大部分的方法。
因为BeautifulSoup对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性,但有时查看它的.name属性是很方便的,所以BeautifulSoup对象包含了一个值为"[document]"的特殊属性.name
print(bs.name)
print(bs.head.name)
4.4 Comment
Comment对象是一个特殊类型的NavigableString对象,其实输出的内容仍然不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦。
if type(bs.strong.string)==Comment:
print(bs.strong.pretify())
else:
print(bs.strong.string)
5 搜索文档树
BeautifulSoup定义了很多搜索方法,这里着重介绍2个:find()和find_all(),其他方法的参数和用法类似,请举一反三
5.1 过滤器
介绍find_all()方法前,先介绍一下过滤器的类型,这些过滤器贯穿整个搜索的API,过滤器可以被用在tag的name中,节点的属性中,字符串中或他们的混合中
5.1.1 字符串
最简单的过滤器是字符串,在搜索方法中传入一个字符串参数,BeautifulSoup会查找与字符串完整匹配的内容,下面的例子用于查找文档中所有的标签
#返回所有的div标签
print(bs.find_all('div'))
如果传入字节码参数,BeautifulSoup会当作utf-8编码,可以传入一段Unicode编码来避免BeautifulSoup解析编码出错
5.1.2 正则表达式
如果传入正则表达式作为参数,BeautifulSoup会通过正则表达式的match()来匹配内容
#返回所有的div标签
print(bs.find_all(re.complie('^div')))
5.1.3 列表
如果传入列表参数,BeautifulSoup会将与列表中任一元素匹配的内容返回
#返回所有匹配到的span a标签
print(bs.find_all(['span','a']))
5.1.4 keyword
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索,如果包含一个名字为id的参数,BeautifulSoup会搜索每个tag的"id"属性
#返回id为welcom的标签
print(bs.find_all(id='welcom'))
5.1.5 True
True可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
5.1.6 按CSS搜索
按照CSS类名搜索tag的功能非常实用,但标识CSS类名的关键字class在Python中是保留字,使用class做参数会导致语法错误,从BeautifulSoup的4.1.1版本开始,可以通过class_参数搜索有指定CSS类名的tag
#返回class等于info的div
print(bs.find_all('div',class_='info'))
5.1.7 按属性搜索
bs.find_all('div',attrs={'class':'info'})
6 CSS选择器(扩展)
soup.select(参数)
表达式 | 说明 |
tag | 选择指定标签 |
* | 选择所有节点 |
#id | 选择id为container的节点 |
.class | 选取所有class包含container的节点 |
li a | 选择所有li下的所有a节点 |
ul + p | (兄弟)选择ul后面的第一个p元素 |
div#id > ul | (父子)选取id为id的div的第一个ul子元素 |
table ~ div | 选取与table相邻的所有div元素 |
a[title] | 选取所有有title属性的a元素 |
a[class='title'] | 选取所有class属性为title值的a |
a[href*=' sxt'] | 选取所有href属性包含sxt的a元素 |
a[href^=' http' ] | 选取所有href属性值以http开头的a元素 |
a[href$=" .png" ] | 选取所有href属性值以.png结尾的a元素 |
input[type="redio"]:checked | 选取选中的hobby的元素 |
1 from bs4 import BeautifulSoup 2 from bs4.element import Comment 3 4 s = ''' 5 <title>学习Python爬虫</title> 6 <div class='info' float='left'>欢迎</div> 7 <div class='info' float='right'> 8 <span id='haha'>好好学习,天天向上</span> 9 <a href='http://sogo.com'></a> 10 <strong><!--这是注释></strong> 11 </div> 12 ''' 13 14 bs = BeautifulSoup(s, 'lxml') 15 16 print(bs.title) # <title>学习Python爬虫</title> 17 print(bs.div) # <div class="info" float="left">欢迎</div> 18 print(bs.div.attrs) # {'float': 'left', 'class': ['info']} 19 print(bs.div.get('class')) # ['info'] 20 print(bs.div['float']) # left 21 print(bs.a['href']) # http://sogo.com 22 23 print(bs.div.string) # 欢迎 24 print(type(bs.div.string)) # <class 'bs4.element.NavigableString'> 25 print(bs.div.text) # 欢迎 26 27 print(bs.strong.string) # None 28 print(type(bs.strong.string)) # <class 'NoneType'> 29 print(bs.strong.text) # 30 31 if type(bs.strong.string) == Comment: 32 print(bs.strong.string) 33 print(bs.strong.prettify()) 34 else: 35 print(bs.strong.text) 36 37 print(bs.strong.prettify()) 38 print('--------------------------find_all--------------------------') 39 print(bs.find_all('title')) # [<title>学习Python爬虫</title>] 40 print(bs.find_all(id='haha')) # [<span id="haha">好好学习,天天向上</span>] 41 print(bs.find_all(class_='info')) 42 ''' 43 [<div class="info" float="left">欢迎</div>, <div class="info" float="right"> 44 <span id="haha">好好学习,天天向上</span> 45 <a href="http://sogo.com"></a> 46 <strong></strong></div>] 47 ''' 48 print(bs.find_all(attrs={'float': 'left'})) # [<div class="info" float="left">欢迎</div>] 49 print('------------------------------CSS--------------------------------------') 50 print(bs.select('title')) # [<title>学习Python爬虫</title>] 51 print(bs.select('#haha')) # [<span id="haha">好好学习,天天向上</span>] 52 print(bs.select('.info')) 53 ''' 54 [<div class="info" float="left">欢迎</div>, <div class="info" float="right"> 55 <span id="haha">好好学习,天天向上</span> 56 <a href="http://sogo.com"></a> 57 <strong></strong></div>] 58 ''' 59 print(bs.select('div span')) # [<span id="haha">好好学习,天天向上</span>] 60 print(bs.select('div > span')) # [<span id="haha">好好学习,天天向上</span>] #效果同上,注:>两边要有空格 61 print(bs.select('div')[1].select('span')) # [<span id="haha">好好学习,天天向上</span>] 62 print(bs.select('div')[1].select('a')) # [<a href="http://sogo.com"></a>] 63 print(bs.select('title')[0].text) # 学习Python爬虫
运行结果:

C:\Users\xiongjiawei\PycharmProjects\Spider\venv\Scripts\python.exe C:/Users/xiongjiawei/PycharmProjects/Spider/13天搞定Python分布式爬虫/第03天/v03-BeautifulSoup的使用.py <title>学习Python爬虫</title> <div class="info" float="left">欢迎</div> {'float': 'left', 'class': ['info']} ['info'] left http://sogo.com 欢迎 <class 'bs4.element.NavigableString'> 欢迎 None <class 'NoneType'> <strong> </strong> --------------------------find_all-------------------------- [<title>学习Python爬虫</title>] [<span id="haha">好好学习,天天向上</span>] [<div class="info" float="left">欢迎</div>, <div class="info" float="right"> <span id="haha">好好学习,天天向上</span> <a href="http://sogo.com"></a> <strong></strong></div>] [<div class="info" float="left">欢迎</div>] ------------------------------CSS-------------------------------------- [<title>学习Python爬虫</title>] [<span id="haha">好好学习,天天向上</span>] [<div class="info" float="left">欢迎</div>, <div class="info" float="right"> <span id="haha">好好学习,天天向上</span> <a href="http://sogo.com"></a> <strong></strong></div>] [<span id="haha">好好学习,天天向上</span>] [<span id="haha">好好学习,天天向上</span>] [<span id="haha">好好学习,天天向上</span>] [<a href="http://sogo.com"></a>] 学习Python爬虫 Process finished with exit code 0
18-xpath的使用
1.介绍
之前BeautifulSoup的用法,这个已经是非常强大的库了,不过还有一些比较流行的解析库,例如lxml,使用的是Xpath语法,同样是效率比较高的解析方法。如果大家对BeautifulSoup使用不太习惯的话,可以尝试下Xpath
官网http://lxml.de/index.html
W3C http://www.w3school.com.cn/xpath/index.asp
2.安装
pip install lxml
3.XPath语法
XPath是一门在XML文档中查找信息的语言。XPath可用来在XML文档中对元素和属性进行遍历。XPath是W3C XSLT标准的主要元素,并且XQuery和XPointer都构建于XPath表达之上
3.1 节点的关系
父(Parent)、子(Children)、同胞(Sibling)、先辈(Ancestor)、后代(Descendant)
3.2 选取节点
3.2.1常用的路径表达式
表达式 | 描述 |
nodename | 选取此节点的所有子节点 |
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
3.2.2 通配符
XPath通配符可用来选取未知的XML元素
通配符 | 描述 | 举例 | 结果 |
* | 匹配任何元素节点 | xpath('div/*') | 获取div下的所有子节点 |
@* | 匹配任何属性节点 | xpath('div[@*]') | 选取所有带属性的div节点 |
node() | 匹配任何类型节点 |
3.2.3 选取若干路径
通过在路径表达式中使用“|”运算符,可以选取若干个路径
表达式 | 结果 |
xpath('//div|//table') | 获取所有的div与table节点 |
3.2.4 谓语
谓语被嵌在方括号内,用来查找某个特定的节点或包含某个制定的值的节点
表达式 | 结果 |
xpath('/body/div[1]') | 选取body下的第1个div节点 |
xpath('/body/div[last()]') | 选取body下的最后1个div节点 |
xpath('/body/div[last()-1]') | 选取body下的倒数第2个节点 |
xpath('/body/div[position()<3]') | 选取body下前两个div节点 |
xpath('/body/div[@class]') | 选取body下带有class属性的div节点 |
xpath('/body/div[@class="main"]') | 选取body下class属性值等于main的div节点 |
xpath('/body/div[price>35.2]') | 选取body下price元素大于35.2的div节点 |
3.2.5 XPath运算符
运算符 | 描述 | 实例 | 返回值 |
计算两个节点集 | //book | //cd | |
+ | 加法 | 1+1 | 2 |
- | 减法 | 1-1 | 0 |
* | 乘法 | 2*3 | 6 |
div | 除法 | 6 div 3 | 2 |
= | 等于 | price=9.8 | 如果price是9.8返回true,否则返回false |
!= | 不等于 | price!=9.8 | 如果price不是9.8返回true,否则返回false |
< | 小于 | price<9.8 | 如果price小于9.8返回true,否则返回false |
<= | 小于或等于 | price<=9.8 | 如果price小于或等于9.8返回true,否则返回false |
> | 大于 | price>9.8 | 如果price大于9.8返回true,否则返回false |
>= | 大于或等于 | price>=9.8 | 如果price大于或等于9.8返回true,否则返回false |
or | 或 | price=9.8 or price=8.9 | 如果price等于9.8或price等于8.9返回true,否则返回false |
and | 与 | price>1 and price<9 | 如果price大于1且小于9返回true,否则返回false |
mod | 计算除法的余数 | 5 mod 2 | 1 |
3.3 使用
3.3.1 小例子
from lxml import etree
text='''
<div>
<ul>
<li class='item-0'><a href='link1.html'>first item</a></li>
<li class='item-1'><a href='link2.html'>second item</a></li>
<li class='item-inactive'><a href='link3.html'>third item</a></li>
<li class='item-1'><a href='link4.html'>fourth item</a></li>
<li class='item-0'><a href='link5.html'>fifth item</a>
</ul>
</div>
'''
html=etree.HTML(text)
result=etree.tostring(html)
print(result)
首先我们使用lxml的etree库,然后利用etree.HTML初始化,然后我们将其打印出来。
其中,这里体现了lxml的一个非常实用的功能就是自动修正html代码,大家应该注意到了,最后一个li标签,是不闭合的。不过,lxml因为继承了libxml2的特性,具有自动修正HTML代码的功能。
所以输出结果是这样的:
<html><body>
<div>
<ul>
<li class='item-0'><a href='link1.html'>first item</a></li>
<li class='item-1'><a href='link2.html'>second item</a></li>
<li class='item-inactive'><a href='link3.html'>third item</a></li>
<li class='item-1'><a href='link4.html'>fourth item</a></li>
<li class='item-0'><a href='link5.html'>fifth item</a></li>
</ul>
</div>
</body></html>
不仅补全了li标签,还添加了body,html标签。文件读取
除了直接读取字符串,还支持从文件读取内容。比如我们新建一个文件叫做hello.html,内容为
<div> <ul> <li class="item-0"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div>
利用parse方法来读取文件
from lxml import etree
html=etree.parse('hello.html')
result=etree.tostring(html,pretty_print=True)
print(result)
同样可以得到相同的结果
3.3.2 XPath具体使用
依然以上一段程序为例
1.获取所有的<li>标签
from lxml import etree html=etree.parse('hello.html') print(type(html)) result=html.xpath('//li') print(result) print(len(result)) print(type(result)) print(type(result[0]))
运行结果
C:\Users\xiongjiawei\PycharmProjects\Spider\venv\Scripts\python.exe C:/Users/xiongjiawei/PycharmProjects/Spider/13天搞定Python分布式爬虫/第03天/v04-xpath的使用.py <class 'lxml.etree._ElementTree'> [<Element li at 0x2039f8658c8>, <Element li at 0x2039f865848>, <Element li at 0x2039f865908>, <Element li at 0x2039f865948>, <Element li at 0x2039f865988>] 5 <class 'list'> <class 'lxml.etree._Element'> Process finished with exit code 0
可见,etree.parse的类型是ElementTree,通过调用xpath以后,得到了一个列表,包含5个<li>元素,每个元素都是Element类型
2.获取<li>标签的所有class
result=html.xpath('//li/@class')
print(result)
运行结果:['item-0', 'item-1', 'item-inactive', 'item-1', 'item-0']
3.获取<li>标签下href为link1.html的<a>标签
案例:
from lxml import etree import requests from fake_useragent import UserAgent url = 'https://www.qidian.com/rank/yuepiao?chn=21' headers = { 'User-Agent': UserAgent().chrome } resp = requests.get(url, headers=headers) html = etree.HTML(resp.text) names = html.xpath('//h4/a/text()') authors = html.xpath('//p[@class="author"]/a[1]/text()') # print(names) # print(authors) ''' for num in range(len(names)): print(names[num],':',authors[num]) ''' for name, author in zip(names, authors): print(name, ':', author)
运行结果

C:\Users\xiongjiawei\PycharmProjects\Spider\venv\Scripts\python.exe C:/Users/xiongjiawei/PycharmProjects/Spider/13天搞定Python分布式爬虫/第03天/v04-xpath的使用.py
诡秘之主 : 爱潜水的乌贼
临渊行 : 宅猪
明日之劫 : 熊狼狗
圣墟 : 辰东
沧元图 : 我吃西红柿
最初进化 : 卷土
史上第一密探 : 沉默的糕点
众神世界 : 永恒之火
万千之心 : 滚开
伏天氏 : 净无痕
我为天帝召唤群雄 : 东天不冷
咫尺之间人尽敌国 : 乘风御剑
斗罗大陆IV终极斗罗 : 唐家三少
我只想安静地打游戏 : 十二翼黑暗炽天使
超神制卡师 : 零下九十度
垂钓之神 : 会狼叫的猪
打造超玄幻 : 李鸿天
儒雅随和的我不是魔头 : 李古丁
我的徒弟都是大反派 : 谋生任转蓬
超神宠兽店 : 古羲
Process finished with exit code 0
19-pyquery的使用
1.1 介绍
如果你对CSS选择器与Jquery有所了解,那么还有个解析库可以使用——pyquery
官网https://pythonhosted.org/pyquery/
1.2 安装
pip install pyquery
1.3 使用方式
1.3.1 初始化方式
- 字符串
from pyquery import PyQuery
doc=PyQuery(str)
print(doc(tagname))
- url
from pyquery import PyQuery
doc=PyQuery(url='http://sogo.com')
print(doc('title'))
- 文件
from pyquery import PyQuery
doc=PyQuery(filename='demo.html')
print(doc(tagname))
1.3.2 选择节点
- 获取当前节点
from pyquery import PyQuery
doc=PyQuery(filename='demo.html')
doc=('#main #top')
- 获取子节点
- 在doc中一层层写出来
- 获取到父标签后使用children方法
from pyquery import PyQuery
doc=PyQuery(filename='demo.html')
doc=('#main #top').children()
- 获取父节点
- 获取到当前节点后使用parent方法
- 获取兄弟节点
- 获取到当前节点后使用sibling方法
1.3.3 获取属性
from pyquery import PyQuery
doc=PyQuery(filename='demo.html')
a=doc('#main #top')
print(a.attrib['href'])
1.3.4 获取内容
from pyquery import PyQuery
doc=PyQuery(filename='demo.html')
div=doc('#main #top')
print(a.html())
print(a.text())
1.3.5 样例
from pyquery import PyQuery #1.可加载一段HTML字符串,或一个HTML文件,或是一个url地址 d=PyQuery('<html><title>hello</title></html>') # d=PyQuery(filename=path_to_html_file) d=PyQuery(url='http://www.sogo.com')#注:此处url似乎必须写全 #2.html()和text()获取相应的HTML或文本块 p=PyQuery('<head><title>hello</title></head>') p('head').html()#返回<title>hello</title> p('head').text()#返回hello #3.根据HTML标签来获取元素 d=PyQuery('<div><p>test 1</p><p>test 2</p></div>') d('p')#返回[<p>,<p>] print(d('p'))#返回<p>test 1</p><p>test 2</p> print(d('p').html())#返回test 1 #注:当获取到的元素不只一个时,html()方法只返回首个元素的相应内容块 #4.eq(index) 根据给定的索引号得到指定元素,接上例,若想得到第二个p标签内的内容,则可以: print(d('p').eq(1).html())#返回test 2 #5.filter() 根据类名、id名得到指定元素,例: d=PyQuery('<div><p id="1">test 1</p><p class="b2">test 2</p></div>') d('p').filter('#1')#返回[<p#1>] d('p').filter('.b2')#返回[<p.2>] #6.find() 查找嵌套元素,例 d=PyQuery('<div><p id="1">test 1</p><p class="b2">test 2</p></div>') d('div').find('p')#返回[<p#1>,<p.2>] d('div').find('p').eq(0)#返回[<p#1>] #7.直接根据类名,id名获取元素,例: d=PyQuery('<div><p id="1">test 1</p><p class="b2">test 2</p></div>') d('#1').html()#返回test 1 d('.b2').html()#返回test 2 #8.获取属性值,例: d=PyQuery('<p id="my_id"><a href="http://sogo.com">hello</a></p>') d('a').attr('href')#返回http://sogo.com d('p').attr('id')#返回my_id #9.修改属性值,例: d('a').attr('herf','http://qq.com')#把href属性修改为http://qq.com #10.addClass(value) 为元素增加类,例: d=PyQuery('<div></div>') d.add_class('my_class')#返回[<div.my_class>] #11.hasClass(name) 返回判断元素是否包含给定的类,例: d=PyQuery('<div class="my_class"></div>') d.has_class('my_class')#返回True #12.children(selector=None) 获取子元素,例 d=PyQuery('<span><p id="1">hello</p><p id="b2">world</p></span>') d.children()#返回[<p#1>,<p#2>] d.children('#2')#返回[<p#2>] #13.parents(selector=None) 获取父元素,例: d=PyQuery('<span><p id="1">hello</p><p id="b2">world</p></span>') d('p').parents()#返回[<span>] d('#1').parents('span')#返回[<span>] d('#1').parents('p')#返回[] #14.clone() 返回一个节点的拷贝 #15.empty() 移除节点内容 #16.nextAll(selector=None) 返回后面全部的元素块,例 d=PyQuery('<p id="1">hello</p><p id="b2">world</p><img src="" />') d('p:first').next_all()#返回[<p#2>,<img>] d('p:last').next_all()#返回[<img>] #17.not_(selector) 返回不匹配选择器的元素,例: d=PyQuery('<p id="1">test 1</p><p id="b2">test 2</p>') d('p').not_('#2')#返回[<p#1>]
实战:
from pyquery import PyQuery import requests from fake_useragent import UserAgent url = 'https://www.xicidaili.com/nn/' headers = { 'User-Agent': UserAgent().random } resp = requests.get(url, headers=headers) doc = PyQuery(resp.text) trs = doc('#ip_list tr') for num in range(1, len(trs)): ip = trs.eq(num).find('td').eq(1).text() port = trs.eq(num).find('td').eq(2).text() type = trs.eq(num).find('td').eq(5).text() print(ip, ' ', port, ' ', type)
运行结果:

C:\Users\xiongjiawei\PycharmProjects\Spider\venv\Scripts\python.exe C:/Users/xiongjiawei/PycharmProjects/Spider/13天搞定Python分布式爬虫/第03天/v06-pyquery的使用2.py 115.216.77.30 9999 HTTPS 60.167.113.137 9999 HTTP 115.216.78.230 9999 HTTP 115.216.76.195 9999 HTTP 115.216.41.198 9999 HTTP 111.79.45.155 9999 HTTP 114.99.12.32 29808 HTTPS 60.167.82.171 9999 HTTP 58.212.40.61 9999 HTTP 110.243.31.184 9999 HTTPS 114.226.161.55 9999 HTTPS 123.169.35.61 9999 HTTPS 114.99.12.179 9999 HTTP 1.196.177.222 9999 HTTP 114.231.41.164 9999 HTTP 112.85.160.13 9999 HTTP 171.35.143.230 9999 HTTP 120.83.107.216 9999 HTTP 114.226.163.42 9999 HTTP 117.95.214.91 9999 HTTPS 122.231.29.178 9999 HTTP 180.122.180.183 9999 HTTP 36.57.87.47 9999 HTTP 180.122.224.209 9999 HTTP 49.70.32.23 9999 HTTPS 218.27.251.248 9999 HTTPS 115.210.68.152 9999 HTTP 115.216.77.238 9999 HTTP 223.199.18.180 9999 HTTPS 223.241.116.88 8010 HTTPS 223.199.30.61 9999 HTTP 111.79.44.162 9999 HTTP 114.99.226.37 9999 HTTP 60.167.112.222 9999 HTTP 106.110.102.51 9999 HTTPS 114.226.160.206 9999 HTTP 59.52.186.217 9999 HTTP 60.167.132.54 808 HTTPS 58.212.43.226 9999 HTTP 182.108.45.182 9999 HTTP 111.79.45.206 9999 HTTP 115.216.79.144 9999 HTTP 36.27.30.18 9999 HTTP 112.85.160.17 9999 HTTPS 182.46.84.219 9999 HTTPS 59.52.187.170 9999 HTTPS 115.216.78.50 9999 HTTPS 123.160.1.102 9999 HTTPS 223.215.186.24 9999 HTTP 182.108.45.89 9999 HTTP 111.79.44.95 9999 HTTP 223.199.25.81 9999 HTTP 223.199.21.131 9999 HTTP 182.32.249.128 9999 HTTP 113.195.157.228 9999 HTTP 58.212.40.134 9999 HTTPS 183.158.138.111 9999 HTTPS 114.226.246.65 9999 HTTP 182.108.47.38 9999 HTTP 59.52.187.184 9999 HTTP 223.199.18.65 9999 HTTP 182.46.87.129 9999 HTTP 123.149.141.25 9999 HTTP 115.216.40.74 9999 HTTP 59.52.187.210 9999 HTTPS 113.195.225.227 9999 HTTPS 183.166.138.53 9999 HTTP 175.43.57.55 9999 HTTP 49.76.15.168 9999 HTTP 115.216.76.30 9999 HTTP 58.212.67.83 9999 HTTP 123.160.1.131 9999 HTTP 59.52.184.173 9999 HTTP 36.27.30.41 9999 HTTPS 36.22.76.195 9999 HTTP 183.154.55.57 9999 HTTP 114.99.15.11 9999 HTTP 60.167.103.215 9999 HTTPS 220.176.46.202 9999 HTTPS 58.253.154.40 9999 HTTPS 27.215.3.35 9999 HTTP 111.79.44.157 9999 HTTP 111.79.44.12 9999 HTTP 36.27.28.99 9999 HTTP 114.99.7.135 9999 HTTP 125.123.143.100 9999 HTTPS 49.70.33.56 9999 HTTPS 114.226.163.253 9999 HTTPS 36.248.129.149 9999 HTTPS 112.85.126.94 9999 HTTPS 223.199.25.210 9999 HTTPS 106.122.169.228 9999 HTTPS 111.79.45.149 9999 HTTP 183.166.138.3 9999 HTTP 111.79.44.40 9999 HTTP 58.212.42.48 9999 HTTP 117.69.234.26 9999 HTTP 60.167.23.140 9999 HTTP 182.46.111.14 9999 HTTP 118.113.244.221 9999 HTTPS Process finished with exit code 0
20-jsonpath的使用
import json s = '{"name":"中国"}' obj = json.loads(s) # loads:字符串->字典 print(obj) # {'name': '中国'} s2 = json.dumps(obj) # dumps:字典->字符串 print(s2) # {"name": "\u4e2d\u56fd"} s2 = json.dumps(obj, ensure_ascii=False) print(s2) # {"name": "中国"} json.dump(obj, open('json.txt', 'w', encoding='utf-8'), ensure_ascii=False) # dump:字典->文件 s3 = json.load(open('json.txt', encoding='utf-8')) # load:json文件->字典 print(s3) # {'name': '中国'}

C:\Users\xiongjiawei\PycharmProjects\Spider\venv\Scripts\python.exe C:/Users/xiongjiawei/PycharmProjects/Spider/13天搞定Python分布式爬虫/第03天/v07-json的使用.py {'name': '中国'} {"name": "\u4e2d\u56fd"} {"name": "中国"} {'name': '中国'} Process finished with exit code 0
4 JsonPath
JsonPath是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript,Python,PHP和Java
JsonPath对于JSON来说,相当于XPath对于XML
安装方法:pip install jsonpath
官方文档:http://goessner.net/articles/JsonPath
5 JsonPath与XPath语法对比
Json结构清晰,可读性高,复杂度低,非常容易匹配,下表中对应了XPath的用法
XPath | JSONPath | 描述 |
/ | $ | 根节点 |
. | @ | 现行节点 |
/ | .or[] | 取子节点 |
.. | n/a | 取父节点,Jsonpath未支持 |
// | .. | 就是不管位置,选择所有符合条件的条件 |
* | * | 匹配所有元素节点 |
@ | n/a | 根据属性访问,Json不支持,因为Json是个Key-value递归结构,不需要。 |
[] | [] | 迭代器标示(可以在里边做简单的迭代操作,如数组下标,根据内容选值等) |
[,] | 支持迭代器中做多选 | |
[] | ?() | 支持过滤操作 |
n/a | () | 支持表达式计算 |
() | n/a | 分组,JsonPath不支持 |
from jsonpath import jsonpath import requests from fake_useragent import UserAgent import json url = "https://www.lagou.com/lbs/getAllCitySearchLabels.json" headers = { "User-Agent": UserAgent().random } response = requests.get(url, headers=headers) names = jsonpath(json.loads(response.text), '$..name') codes = jsonpath(response.json(), '$..code') print(names) print(codes)
运行结果:

C:\Users\xiongjiawei\PycharmProjects\Spider\venv\Scripts\python.exe C:/Users/xiongjiawei/PycharmProjects/Spider/13天搞定Python分布式爬虫/第03天/v08-jsonpath的使用.py ['广州', '贵阳', '桂林', '赣州', '广元', '贵港', '广安', '甘孜藏族自治州', '西安', '厦门', '徐州', '新乡', '西宁', '咸阳', '香港特别行政区', '孝感', '许昌', '邢台', '湘潭', '襄阳', '咸宁', '信阳', '西双版纳', '宣城', '忻州', '湘西土家族苗族自治州', '鄂尔多斯', '鄂州', '恩施', '兰州', '廊坊', '临沂', '洛阳', '柳州', '聊城', '拉萨', '龙岩', '六安', '连云港', '丽水', '乐山', '临汾', '凉山彝族自治州', '漯河', '丽江', '莱芜', '六盘水', '泸州', '吕梁', '娄底', '辽源', '辽阳', '郑州', '珠海', '中山', '株洲', '淄博', '湛江', '肇庆', '遵义', '镇江', '漳州', '驻马店', '周口', '张家口', '枣庄', '舟山', '长治', '资阳', '张掖', '昭通', '自贡', '张家界', '佛山', '福州', '阜阳', '抚州', '抚顺', '阜新', '深圳', '上海', '苏州', '沈阳', '石家庄', '汕头', '绍兴', '宿迁', '三亚', '上饶', '韶关', '遂宁', '十堰', '商丘', '宿州', '邵阳', '随州', '三门峡', '三沙', '汕尾', '朔州', '三明', '烟台', '扬州', '银川', '宜昌', '盐城', '岳阳', '宜春', '玉林', '运城', '榆林', '宜宾', '云浮', '阳江', '永州', '营口', '延安', '益阳', '伊犁', '玉溪', '雅安', '鹰潭', '济南', '金华', '江门', '嘉兴', '济宁', '晋中', '九江', '焦作', '吉林', '荆州', '揭阳', '荆门', '景德镇', '吉安', '晋城', '佳木斯', '锦州', '金昌', '酒泉', '昆明', '开封', '克拉玛依', '喀什', '绵阳', '马鞍山', '茂名', '梅州', '眉山', '牡丹江', '武汉', '无锡', '温州', '潍坊', '乌鲁木齐', '芜湖', '威海', '渭南', '吴忠', '文山', '梧州', '乌海', '天津', '太原', '唐山', '台州', '泰安', '泰州', '天水', '台湾', '铜陵', '通辽', '塔城', '铜川', '铜仁', '通化', '铁岭', '东莞', '大连', '德阳', '东营', '德州', '大庆', '大理', '达州', '大同', '丹东', '儋州', '定西', '德宏', '迪庆', '杭州', '合肥', '惠州', '哈尔滨', '海口', '呼和浩特', '海外', '菏泽', '淮安', '邯郸', '河源', '湖州', '衡阳', '黄石', '怀化', '黄冈', '衡水', '淮南', '呼伦贝尔', '淮北', '河池', '黄山', '鹤岗', '葫芦岛', '海东', '汉中', '日照', '青岛', '泉州', '清远', '秦皇岛', '衢州', '曲靖', '黔东南', '黔西南', '钦州', '齐齐哈尔', '庆阳', '黔南', '南京', '宁波', '南昌', '南宁', '南通', '南充', '南阳', '宁德', '内江', '南平', '濮阳', '萍乡', '莆田', '盘锦', '平顶山', '攀枝花', '成都', '长沙', '重庆', '长春', '常州', '沧州', '潮州', '赤峰', '郴州', '滁州', '常德', '昌吉', '池州', '楚雄', '朝阳', '承德', '鞍山', '阿勒泰', '澳门特别行政区', '安阳', '安庆', '阿克苏', '安康', '阿拉善盟', '北京', '保定', '蚌埠', '包头', '滨州', '宝鸡', '亳州', '百色', '巴中', '毕节', '北海', '巴音郭楞', '保山', '白城', '本溪', '巴彦淖尔'] ['200100000', '240100000', '211200000', '150500000', '231900000', '210700000', '230200000', '230800000', '270100000', '141100000', '111900000', '171700000', '290100000', '270900000', '320100000', '181800000', '171100000', '051200000', '191200000', '181500000', '181000000', '170500000', '250800000', '130700000', '060500000', '191400000', '070900000', '181600000', '180300000', '280100000', '050700000', '162800000', '171300000', '211300000', '161500000', '260100000', '140400000', '130400000', '112400000', '122800000', '232200000', '060400000', '230900000', '171000000', '250500000', '162700000', '240200000', '231600000', '060300000', '190200000', '090800000', '080900000', '170100000', '201800000', '200400000', '191300000', '161800000', '202200000', '202400000', '240300000', '112800000', '140600000', '170700000', '170600000', '051000000', '161900000', '122600000', '061000000', '230600000', '280800000', '251300000', '231400000', '190700000', '202000000', '140100000', '131000000', '150200000', '081500000', '081000000', '201700000', '020100000', '112100000', '080100000', '050100000', '201900000', '122300000', '113000000', '221800000', '151100000', '201600000', '232000000', '181300000', '170400000', '130200000', '191000000', '180200000', '170200000', '220200000', '201500000', '060800000', '140900000', '162100000', '112700000', '300100000', '181400000', '112600000', '190900000', '150300000', '210600000', '060600000', '270500000', '231200000', '200700000', '201300000', '190400000', '081100000', '270700000', '190600000', '310200000', '251500000', '230400000', '150600000', '160100000', '122400000', '202100000', '122100000', '162300000', '060700000', '150800000', '171800000', '091000000', '181900000', '200600000', '181700000', '151000000', '150400000', '060900000', '101100000', '081200000', '281200000', '280600000', '250100000', '171200000', '311200000', '311100000', '231800000', '131500000', '202300000', '202600000', '231300000', '100900000', '180100000', '111800000', '122000000', '162200000', '310100000', '131200000', '162500000', '270800000', '300300000', '251000000', '211100000', '071200000', '030100000', '060100000', '051500000', '122700000', '162400000', '112900000', '281000000', '340100000', '131700000', '071000000', '310300000', '271100000', '240500000', '090700000', '080700000', '200300000', '081700000', '231700000', '162000000', '161600000', '101300000', '250700000', '230300000', '061200000', '081300000', '220201000', '280400000', '250600000', '250300000', '120100000', '130100000', '202500000', '100100000', '220100000', '070100000', '350100000', '160200000', '112500000', '051300000', '201400000', '122200000', '191100000', '181200000', '190300000', '181100000', '050600000', '131400000', '070800000', '131600000', '210300000', '131900000', '101500000', '080500000', '290200000', '270600000', '162600000', '161700000', '140800000', '200200000', '051400000', '122500000', '251600000', '240800000', '240600000', '210800000', '101700000', '280500000', '240900000', '110100000', '121900000', '150100000', '210100000', '112300000', '232300000', '170300000', '140300000', '232100000', '140500000', '171900000', '150900000', '141000000', '080800000', '171400000', '231500000', '230100000', '190100000', '040100000', '090100000', '112000000', '050800000', '200500000', '071100000', '190500000', '131100000', '190800000', '311500000', '130600000', '251200000', '080600000', '050900000', '081600000', '310400000', '330100000', '171500000', '131800000', '311800000', '270400000', '070300000', '010100000', '051100000', '131300000', '071300000', '161400000', '271000000', '130500000', '210500000', '230500000', '240700000', '211000000', '311700000', '251400000', '090400000', '081400000', '070400000'] Process finished with exit code 0
……