爬虫-正则表达式-lxml$xpath

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 对于元组对象,有以下两种情况:

  1. 对象全部是不可变的数据类型,那么copy.copy()和copy.deepcopy()的结果是一样的,都是引用的赋值,即指向
  2. 如果对象最外围是不可变类型,但内部包含了可变类型的数据,对于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标签,ali后代结点
    • //li/a 查找所有的li标签下面的a标签,ali子结点
  • @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)

数据提取的通用方式:先分组,再提取

猜你喜欢

转载自blog.csdn.net/weixin_44090435/article/details/86437761