1. 正则表达式
1.1 单个字符
\d
数字0-9\s
空白字符 空格\t
\n
\w
单词字符.
除了\n
的任意字符- [a-d0-9] 匹配a-d或者0-9中任意一个
1.2 多个字符
- {m,n}前一个字符出现m-n次(包含m和n)
*
匹配前一个字符任意次(0,1,多次)+
匹配前一个字符至少一次(1或者多次)?
匹配前一个字符0次或1次
1.3 re模块
-
re.findall() # 查找所有
-
re.sub() # 替换,数据清洗的时候很常用
-
re.compile() # 先编译后匹配,提高匹配效率
re.findall(“regex”),如果正则表达式进行了分组,需要考虑返回的数据情况,
- 一个分组,返回包含字符串的列表
- 多个分组,返回包含元组的列表,元组内时多个分组匹配到的字符串
r的用途
忽略转义符号\
带来的影响,为了表示原字符本身的话,直接在正则表达式前面加上r
即可
windwos下的文件路径需要加上r
2. 深拷贝与浅拷贝
2.1 在Python中,对象的赋值就是简单的对象引用指向
b = [1,2,3]
a = b
那么a和b的引用地址是一样了,指向了同一块内存地址,a即为b的一个别名
2.2 浅拷贝是对象的外层拷贝,即只进行第一层的拷贝,
在浅拷贝的情况下,只是拷贝了最外围的对象本身,内部的元素都只是引用的赋值,即指向
In[2]: a = [1, 2]
In[3]: b = [3, 4]
In[5]: c = [a,b]
In[6]: d = copy.copy(c)
In[7]: id(d)
Out[7]: 1668591779912
In[8]: id(c)
Out[8]: 1668591213896
In[9]: a.append(5)
In[10]: c
Out[10]: [[1, 2, 5], [3, 4]]
In[11]: d
Out[11]: [[1, 2, 5], [3, 4]]
常见的浅拷贝,除了copy.copy(),还有以下函数:
- 切片
- list()
- 列表推导式
- dict.copy()
2.3 深拷贝是对外围和内部元素都进行了拷贝对象本身,而不是指向
利用copy中的deepcopy方法进行拷贝就叫做深拷贝
In[12]: e = copy.deepcopy(c)
In[13]: id(c)
Out[13]: 1668591213896
In[14]: id(e)
Out[14]: 1668591153224
In[15]: a.append(6)
In[16]: c
Out[16]: [[1, 2, 5, 6], [3, 4]]
In[17]: e
Out[17]: [[1, 2, 5], [3, 4]]
In[18]: id(c[0])
Out[18]: 1668590642760
In[19]: id(e[0])
Out[19]: 1668591296968
注意:对于数字,字符串等,没有被拷贝的说法,即便是用深拷贝,查看id的话也是一样的。
扫描二维码关注公众号,回复:
4977240 查看本文章
In[2]: a = 1
In[3]: b = "haha"
In[5]: c = copy.copy(a)
In[6]: id(a)
Out[6]: 1903193104
In[7]: id(c)
Out[7]: 1903193104
In[8]: d = copy.copy(b)
In[9]: id(b)
Out[9]: 1363639310744
In[10]: id(d)
Out[10]: 1363639310744
In[11]: c = copy.deepcopy(a)
In[12]: id(c)
Out[12]: 1903193104
In[13]: d = copy.deepcopy(b)
In[14]: id(d)
Out[14]: 1363639310744
2.4 对于元组对象,有以下两种情况:
- 对象全部是不可变的数据类型,那么copy.copy()和copy.deepcopy()的结果是一样的,都是引用的赋值,即指向
- 如果对象最外围是不可变类型,但内部包含了可变类型的数据,对于copy.copy()还是指向,但对于copy.deepcopy()则是深度拷贝
# 代码
In[3]: a = [11,22]
In[4]: b= [33,44]
In[5]: c = (a,b)
In[6]: d = copy.copy(c)
In[7]: d
Out[7]: ([11, 22], [33, 44])
In[8]: id(d)
Out[8]: 3044966714056
In[9]: id(c)
Out[9]: 3044966714056
In[10]: e = copy.deepcopy(c)
In[11]: id(e)
Out[11]: 3044968636488
3. xpath
-
/
表示根路径或者结点之间的过渡 -
//
从任意位置开始查找所有的指定标签//a
查找文档中所有的a标签/li//a
找根结点下面的li
标签下面的所有a
标签,a
是li
的后代结点//li/a
查找所有的li
标签下面的a
标签,a
是li
的子结点
-
@attr
获取标签的指定属性值//a/@href
获取所有a
标签的href
值/li//img/@src
获取根结点下面的li
标签下面的img
标签的src
属性值/html/head/link/@href
-
text()
获取标签的文本内容//a/text()
获取所有a标签的文本值//li//text()
获取所有li
标签下所有的文本内容
xpath定位
//a[@class='bt']
所有a标签中class属性值为bt的//a[text()='下一页']/@herf
找文本为下一页的a标签的href属性值//a[1]
第一个//a[last()]
最后一个//a[postions()<3]
前2个
4. lxml模块的使用
pip install lxml
from lxml import etree
text = '''<html> <div> <ul>
<li class="item-1"><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> '''
# 将网页内容加载,返回一个Element对象,具有xpath方法
el = etree.HTML(text)
# 将element对象还原为网页数据的字符串
print(etree.tostring(el).decode())
# xpath表达式如果是定位标签,返回的结果是一个以element为元素的列表
li_list = el.xpath("//li[@class='item-1']")
print(li_list)
# 建议这样写
li_list[0].xpath("./a/@href")
# 不建议这样写
li_list[0].xpath("a/@href")
# xpath表达式如果是获取属性值或者文本。返回的结果是一个以字符串为元素的列表
href_list = el.xpath("//li[@class='item-1']/a/text()")
print(href_list)
数据提取的通用方式:先分组,再提取