一、requests库方法(部分)
1、会话维持
在Python爬取页面时,有一些页面需要登录才能访问,requests库中有两种方式可以解决这个问题。
# 第一种方式Cookie
import requests
headers = {
'Cookie':'....',
'Host':'....',
'User-Agent':'.....'
}
resp = requests.get('http://www.xxx.com', headers=herders) # 携带上所需要的Cookie即可
print(resp.text)
# 第二种方式Session
import requests
headers = {
'Cookie':'',
'Host':'',
'User-Agent':''
}
session = requests.Session() # 后续使用session变量名用于保持Cookie传递
# 和设置Cookie相比这种方式的好处是,后续请求不需要携带headers字段
resp = session.get('http://www.xxx.com', headers=herders)
resp_test = session.get('http://www.xxx.com/pag') # Ps:后续不需要携带headers字段,也可保持Cookie的传递。
print(resp.text)
2、代理
网站对于请求频繁的IP可能会弹出验证码,或者跳转登录页面,也可能会直接封禁客户端的IP,这时候就要用到代理。
import requests
proxies = {
'http':'http://10.10.1.10:3128',,
'https':'https://10.10.1.10:1080'
}
requests.get('https://taobao.com', proxies=proxies)
# 有些网站由于没有安全证书会弹出不是私密连接
response = requests.get('http://xxx.com', verify=False) # 通过verify设置为False不验证证书
# 设置timeout请求等待响应超时的时间
response = requests.get('http://xxx.com', timeout=1)
3、Prepared Request
在requests库中还可以使用Request对象来独立请求,可以将请求当作独立的对象看待,在进行队列调度时会非常方便,用法如下:
from requests import Request, Session
url = 'http://xxx.com'
s = Session()
req = Request('POST', url) # 里面可以加上data、headers等参数
prepped = s.prepare_request(req) # 通过Session这个方法将Request对象转换为Prepared Request对象
r = s.send(prepped) # 发送请求
print(r.text)
二、re库正则表达式(部分)
正则表达式用于爬虫的HTML提取解析非常方便,通过Python中的re模块就可以非常方便的提取所需要的数据。
1、re.match函数(开头匹配:一般用于检查某个字符串是否符合正则匹配)
语法:re.match(pattern, string, flags=0)
pattern | string |
---|---|
匹配的正则表达式 | 要匹配的字符串 |
flags(修饰符):
- 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 为了增加可读性,忽略空格和 # 后面的注释
import re
result = re.match("itcast","itcast.cn")
result.group()
>>>'itcast'
# 第二种使用方法group(1),括号代表分组
content = 'Hello 123456 World_This is a Regex Demo'
result = re.match('Hello\s(\d+)\sWorld', content)
print(result.group())
>>> 'Hello 123456 World'
print(result.group(1)) # 提取分组里面的内容
>>>'123456'
2、贪婪与非贪婪
贪婪与非贪婪匹配差别是:.*(贪婪模式)会尽可能多的去匹配字符;非贪婪模式即在贪婪模式后面加上?匹配尽可能少的字符串,在做匹配时,字符串中间尽可能使用非贪婪模式匹配,以免出现匹配结果缺失的情况。
3、search方法(全量匹配)
match()方法是从字符串的开头匹配的,一旦开头不匹配,整个匹配就不能成功。
import re
content = 'Exce Hello 121'
result = re.match('Hello.*', content)
result = re.search('Hello.*', content, re.S) # re.S可以匹配换行
print(result)
>>> None # match匹配结果
>>> 'Hello 121' # search匹配结果
4、findall方法(全局匹配)
search方法可以返回匹配的第一个结果,但是在实际爬虫中,我就是需要多个匹配返回结果怎么办呢?这时候就需要借助到findall函数方法了,这个方法会返回正则表达式匹配的所有结果。
import re
pattern=r'mr_\w+'
string='MR_SHOP mr_shop'
match=re.findall(pattern,string,re.I)
print(match)
>>>['MR_SHOP', 'mr_shop']
for ma in match:
print(ma) # 循环打印匹配的结果,可以用列表索引取值ma[1]
5、sub方法(替换)
如果是为了替换一部分字段,或者替换为空值,使用字符串的replace方法太繁琐了,可以借助sub方法匹配替换。
import re
content = '32aKds3l3e32reva'
result = re.sub('\d+', '', content)
print(result)
>>> 'aKdslereva'
6、compile方法
这个方法主要是将正则匹配规则编译为表达式对象,方便在后面的正则表示式匹配中去复用。
import re
content1 = '2023-12-23 15:00'
content2 = '2023-2-5 12:00'
pattern = re.compile('\d{2}:\d{2}') # 可以在后面加上修饰符,这样后面的就不需要加上修饰符了
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
print(result1, result2)
>>> '2023-12-23'
>>> '2023-2-5'
7、常用的正则匹配规则(部分)
描述 | 模式 |
---|---|
\w | 匹配字母、数字及下划线 |
\s | 匹配任意空白字符,等价于[\t\n\r\f],即匹配换行符、制表符等 |
\d | 匹配任意数字,等价于[0-9] |
. | 匹配任意字符,除了换行符,若指定re.S,则可以匹配到包括换行符的任意字符 |
* | 匹配前面0个或者多个表达式 |
+ | 匹配前面一个或多个表达式 |
? | 匹配0个或1个前面的正则表达式定义的片段,非贪婪模式 |
精确匹配到n个前面的表达式 | |
( ) | 提取匹配括号内的表达式,也表示为一个组 |
三、Xpath解析
xpath常用匹配规则如下表所示:
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从当前节点选取直接子节点 |
// | 从当前节点选取子孙节点 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
1、lxml库运用(部分)
在Python中使用Xpath可以使用lxml这个库来匹配网页中的各个节点,lxml不但能匹配HTML文档还能匹配XML文档,当然还能创建XML文档,这里只对运用HTML文档的匹配进行说明。
from lxml import etree
html = etree.parse('./test.html', etree.HTMLParser()) # (1)读取本地文本文件进行解析
ewsult = html.xpaht('//li/a')
print(result)
text = '''
<li class="li li-first" name="item"><a href="link.html">first item</a></li>
................
'''
html = etree.HTML(text) # (2) 通过HTML类对爬取的网页进行初始化
result = html.xpath('//li[@class=li li-first]/a')
result = html.xpath('//li[1]/a/text()') # li[1]通过索引获取指定次序的节点,text()匹配文本
result = html.xpath('//li[last()]/a/text()') # last()匹配排名最后li节点,last()-2用于匹配倒数第三个节点
result = html.xpath('//li[position()<3]/a/text()') # position()<3匹配位置小于3的li节点,即1和2
# -----------------------------------------
result = html.xpath('//li[1]/ancestor::*') # ancestor::*轴用于获取双冒号后面规则的祖先节点
result = html.xpath('//li[1]/attribute::*') # attribute::*轴用于双冒号后面规则:获取li节点的所有属性
result = html.xpath('//li[1]/child::a[@herf="link.html"]') # child轴获取直接子节点,获取属性为herf="link.html"的a子节点
result = html.xpath('//li[1]/parent::*') #parent::*轴选取父节点。
四、Beautiful Soup解析库运用(部分)
Beautiful Soup库是一个通过网页的结构和属性等特性来解析网页。通过它可以不用去写一些复杂的正则表达式,只需要简单几条语句,就可以完成对网页的某个元素的提取。
解析器 | 使用方法 | 优势 |
---|---|---|
Python标准库 | BeautifulSoup(html, “html.parser”) | 1、Python的内置标准库 2、执行速度适中 3、文档容错能力强 |
lxml HTML解析器 | BeautifulSoup(html, “lxml”) | 1.速度快 2.文档容错能力强 |
lxml XML解析器 | BeautifulSoup(html, [“lxml”, “xml”]) BeautifulSoup(html, “xml”) | 1.速度快 2.唯一支持XML的解析器 |
html5lib | BeautifulSoup(html, “html5lib”) | 1.最好的容错性 2.以浏览器的方式解析文档 3.生成HTML5的文档 |
Ps:一般用于爬虫来解析HTML网页用的是第一个和第二个方法。
1、基本用法
from bs4 import BeautifulSoup
# 1、基本用法----------------------------------------------------
soup = BeautifulSoup(html, "lxml") # 用lxml HTML解析器解析速度快一些,用html.parser也没问题。
print(soup.prettify()) # 把需要解析的字符串一标准格式缩进输出
print(soup.title.string) # 通过title方法提取title节点和文本内容,通过string得到里面的文本
# 2、节点选择----------------------------------------------------
print(soup.div)
# >>> <div class="..." id="...">.........</div>
print(soup.head, soup.p) # 直接(.节点名)可以直接获取节点即里面的属性和文本
# 3、提取信息----------------------------------------------------
# (1)获取节点名称
print(soup.title.name) # 通过name属性获取节点名:title
# (2)获取属性attrs方法
print(soup.p.attrs) # 通过attrs获取属性
print(soup.p.attrs['name'])
'''
>>> {'class':['title'], 'name':'dromouse'}
>>> dromouse
'''
# (2)获取属性不使用attrs简单方法
print(soup.p['name'])
print(soup.p['class'])
'''
>>> dromouse
>>> ['title']
返回值不一样是由于class属性值不具有唯一性,一个节点可以有多个class属性值,name值唯一。
'''
# (3)嵌套选择
pirnt(soup.head.title.string)
# (4)关联选择(由于多个节点嵌套)
print(soup.p.contents)
# >>> 输出p节点的直接子节点宜列表输出。
2、方法选择器
from bs4 import BeautifulSoup
import re
soup = BeautifulSoup(html, "lxml")
# (1)find_all()方法:返回所有匹配到的元素列表———————————————————————————————————
print(soup.find_all(name='li')) # 不写name关键字也行
# >>> 输出的结果为所有的li标签,返回值类型为列表
for ul in find_all(name='ul'):
print(ul.find_all(name='li'))
# >>> 输出的结果为ul标签下的li标签(嵌套)
print(soup.find_all(attrs={'id':'list-1'}))
print(soup.find_all(attrs={'name':'elements'})
print(soup.find_all(id='list-1')) # 常用的如id、class属性,不需要通过attrs传递
print(soup.find_all(clss_=' element'))
# >>> 输出结果为列表类型的、属性为指定属性的节点
print(soup.find_all(text=re.compile('link'))) # 匹配节点的文本,text的值可以是文本和正则表达式
# >>> 输出结果为['str', 'str'],Ps:一般不常用。
# (1)find()方法:返回第一个匹配到的元素-------———————————————————————————————————
print(soup.find(name='ul'))
print(soup.find(class_='element'))
# >>> 结果不再是列表类型,而是第一个匹配到的节点元素。
还有其他方法选择器,,用法与上面两种一样,只是查询的范围不同,下面简单说明一下:
- find_parents( )和find_parent( ):前者返回所有的祖先节点,后者返回直接父节点。
- find_next_siblings( )和find_previous_sibling( ):前者返回前面所有的兄弟节点,后者返回前面第一个兄弟节点。
- find_all_next( )和find__next( ):前者返回节点后所有符合条件的节点,后者返回第一个符合条件的节点。
- find_all_previous( )和find_previous( ):前者返回节点前所有符合条件的节点,后者返回第一个符合条件的节点。
3、CSS选择器
使用CSS选择器只需要调用select( )方法,传入相应的CSS选择器即可,示例如下:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
# (1)基本用法————————————————————————————————————
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))
# (2)嵌套选择————————————————————————————————————
for ul in soup.select('ul'):
print(ul.select('li'))
# (3)获取属性值————————————————————————————————————
for ul in soup.select('ul'):
print(ul['id'])
print(ul.attrs['id'])
print(ul.get('src'))
# (4)获取文本————————————————————————————————————
for li in soup.select('li'):
print(li.get_text())
print(li.string)
五、pyquery库(部分)
虽然Beautiful Soup的CSS选择器已经很好了,但是还是有另外一种使用CSS选择器来解析的库,而且相比起来非常好用。
和Beautiful Soup一样,初始化pyquery的时候,也是需要传入一个HTML文本来初始化一个PyQuery对象。它的初始化方法有很多,比如直接传入字符串、传入URL,传入文件名等等。
1、初始化
from pyquery import PyQuery as pq
html = '''
<div>
<span>...</span>
<li>...</li>
<li>...</li>
<li>...</li>
</div>
'''
# (1)字符串初始化————————————————————————————
doc = pq(html)
print(doc('li')) # 返回所有的li标签
# (2)URL初始化———————————————————————————————
doc = pq(url='http://www.xxx.com')
print(doc('title')) # 返回网站title标签
doc = pq(requests.get('http://www.xxx.com').text) # 与上面的字符串初始化方法是一样的
print(doc('title')) # 返回网站title标签
# (3)文件初始化——————————————————————————————
doc = pq(filename='demo.html')
print(doc('title'))
2、基本CSS选择器
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('#container .list li'))
# >>> 输出id为container内部class为list下内部的li节点
# (1)查找子孙节点:find()方法————————————————————————————————————
items = doc('.list')
lis = items.find('li')
print(lis)
# >>> 选取class为list的节点,然后选择其子节点li节点
lis = items.children() # children值查找符合条件的子节点,find则是查找符合条件的子孙节点
# (2)查找父节点:parent()方法————————————————————————————————————
doc = pq(html)
items = doc('.list')
container = items.parent()
print(container) # 通过找到class为list的节点,然后使用parent()找到其直接父节点
# parents()方法则是用来找到其祖先节点
# (3)查找兄弟节点:siblings()方法,用法同上——————————————————————————
# (4)遍历:items()方法—————————————————————————————————————————————
lis = doc('li').items()
for li in lis:
print(li)
# (5)获取属性,通过attr()方法———————————————————————————————————————
a = doc('a')
print(a.attr('href'))
print(a.attr.href) # 两种方法都能获取到属性,但是只能获取到一个
for item in a.items():
print(item.attr('href')) # 通过遍历方法就能同时获取到多个属性
# (6)获取文本:text()、html()方法————————————————————————————————————————————
a = doc('.item-0.active a')
print(a.text())
print(a.html())
# 它们之间的区别就是text()用于获取标签夹带的文本,html()则获取a下面的标签节点。
3、节点操作(部分举例)
pyquery提供了一系列方法来对节点进行动态修改,比如为某一个节点添加一个class,移除某个节点等。
- addClass和removeClass
from pyquery import PyQuery as pq
html = '<div>........</div>'
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.removeClass('.active')
print(li)
li.addClass('.active')
print(li)
'''
三次打印的结果如下:
<li class="item-0 active">.....</li>
<li class="item-0">.....</li>
<li class="item-0 active">.....</li>
'''
# addClass和removeClass方法可以动态改变节点的class属性。
# 当然,除了操作class属性外,也可以用attr()方法对属性进行操作。还可以用text()和html()
li = doc('.item-0.active')
li.attr('name', 'link') # 对节点添加name属性,值为link
li.text('changed item') # 对节点内的内容改变为changed item
li.html('<span>changed item</span>') # 在节点内部添加标签
# attr()传递一个参数用于获取属性,两个参数则是修改。text()、html()传递参数则是用于赋值。
remove()方法
doc = pq(html)
wrap = doc('.wrap')
wrap.find('p').remove()
print(wrap.text())
# 这个方法主要是为了更加方便的提取指定参数值,把多余的节点进行删除,方便提取想要的节点。
4、伪类选择器(部分)
CSS选择器之所以强大,一个非常重要的原因就是它支持多种多样的伪类选择器,例如选择第一个节点、最后一个节点、奇偶数节点等等。
from pyquery import PyQuery as pq
html = '<div>.....</div>'
doc = pq(html)
li = doc('li:first-child') # 选择第一个li节点
li = doc('li:last-child') # 选择最后一个li节点
li = doc('li:nth-child(2)') # 第二个li节点
li = doc('li:gt(2)') # 第三个之后的li节点、-n)B=u9-'80y