Python网络爬虫学习笔记 -第三章:爬虫数据提取

课程地址 https://edu.csdn.net/course/detail/24756/280664

文章目录

  • XPath语法和lxml模块
    • 什么是XPath?
    • XPath节点
    • XPath语法
    • lxml库
    • 在lxml中使用xpath
  • BeautifulSoup4库
    • 安装和文档
    • 几大解析工具对比
    • 简单使用
    • 常见的四种对象
    • contents和children:
    • string和strings、stripped_strings属性以及get_text方法
    • find_all的使用:
    • find与find_all的区别:
    • 使用find和find_all的过滤条件:
    • 获取标签的属性:
    • CSS选择器:
      • select方法:
        • (1)通过标签名查找:
        • (2)通过类名查找:
        • (3)通过id查找:
        • (4)组合查找:
        • (5)通过属性查找:
        • (6)获取内容
  • 正则表达式:
    • 单字符匹配:
    • 多字符匹配:
    • 正则表达式案例:
    • 开始/结束/贪婪和非贪婪:
    • 转义字符和原生字符串:
    • 分组:
    • re中常用的函数:

XPath语法和lxml模块

什么是XPath?

xpath(XML Path Language)是一门在XML和HTML文档中查找信息 的语言,可用来在XML和HTML文档中对元素和属性进行遍历。

XPath节点

在 XPath 中,有七种类型的节点:元素、属性、文本、命名 空间、处理指令、注释以及文档(根)节点。XML 文档是被 作为节点树来对待的。树的根被称为文档节点或者根节点。

XPath语法

使用方式:
使用//获取整个页面当中的元素,然后写标签名,然后再写谓词进行提取,比如:

//title[@lang='en']

需要注意的知识点:

  1. /和//的区别:/代表只获取子节点,//获取子孙节点,当然也要视情况而定。
  2. contains:有时候某个属性中包含了多个值,那么可以使用contains函数,示例如下:
//title[contains(@lang,'en')]
  1. 谓词中下标是从1开始,而不是从0开始的

lxml库

lxml是一个HTML/XML的解析器,主要的功能是如何解析和提取HTML/XML数据。
基本使用:

from lxml import etree

text = '''

'''
# 将字符串解析为html文档
html = etree.HTML(text)
print(html)
# 按字符串序列化html
result = etree.tostring(html).decode('utf-8')
print(result)

从文件中读取html代码:

#读取
html = etree.parse('hello.html')
result = etree.tostring(html).decode('utf-8')
print(result)

在lxml中使用xpath

<!-- hello.html -->
>>
>
    >
         
  • -0">>first item>>
  • -1">>second item>>
  • -inactive">>>third item>>>
  • -1">>fourth item>>
  • -0">>fifth item>> > > >>
  • 语法练习

    from lxml import etree
    html = etree.parse('hello.html')
    # 获取所有li标签:
    result = html.xpath('//li')
    print(result)
    # for i in result:
    #     print(etree.tostring(i))
    # 获取所有li元素下的所有class属性的值:
    # result = html.xpath('//li/@class')
    # print(result)
    # 获取li标签下href为www.baidu.com的a标签:
    # result = html.xpath('//li/a[@href="www.baidu.com"]')
    # print(result)
    # 获取li标签下所有span标签:
    # result = html.xpath('//li//span')
    # print(result)
    # 获取li标签下的a标签里的所有class:
    # result = html.xpath('//li/a//@class')
    # print(result)
    # 获取最后一个li的a的href属性对应的值:
    # result = html.xpath('//li[last()]/a/@href')
    # print(result)
    # 获取倒数第二个li元素的内容:
    # result = html.xpath('//li[last()-1]/a')
    # print(result)
    # print(result[0].text)
    # 获取倒数第二个li元素的内容的第二种方式:
    result = html.xpath('//li[last()-1]/a/text()')
    print(result)
    

    BeautifulSoup4库

    安装和文档

    安装:pip install bs4
    中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html

    几大解析工具对比

    Python网络爬虫学习笔记 -第三章:爬虫数据提取_第1张图片

    简单使用

    from bs4 import BeautifulSoup
    
    html = "<html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
    <p class="story">...</p>"
    soup = BeautifulSoup(html,'lxml')
    print(soup.prettify())
    

    常见的四种对象

    1. Tag:
      Tag 通俗点讲就是 HTML 中的一个个标签。我们可以利用 soup 加标签名轻松地获取 这些标签的内容,这些对象的类型是bs4.element.Tag。但是注意,它查找的是在所有 内容中的第一个符合要求的标签。
    2. NavigableString:
      如果拿到标签后,还想获取标签中的内容。那么可以通过tag.string获取标签中的文字。
    3. BeautifulSoup:
      BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象, 它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法.
    4. Comment:
      Tag , NavigableString , BeautifulSoup 几乎覆盖了html和xml中的所有内容,但是还 有一些特殊对象.容易让人担心的内容是文档的注释部分
      Comment 对象是一个特殊类型的 NavigableString 对象

    contents和children:

    返回某个标签下的直接子元素,其中也包括字符串。他们两的区别是:contents返回来的是一个列表,children返回的是一个迭代器。

    string和strings、stripped_strings属性以及get_text方法

    1. string:获取某个标签下的非标签字符串。返回来的是个字符串。如果这个标签下有多行字符,那么就不能获取到了。
    2. strings:获取某个标签下的子孙非标签字符串。返回来的是个生成器。
    3. stripped_strings:获取某个标签下的子孙非标签字符串,会去掉空白字符。返回来的是个生成器。
    4. get_text:获取某个标签下的子孙非标签字符串,以普通字符串形式返回

    find_all的使用:

    1. 在提取标签的时候,第一个参数是标签的名字。然后如果在提取标签的时候想要使用标签属性进行过滤,那么可以在这个方法中通过关键字参数的形式,将属性的名字以及对应的值传进去。或者是使用attrs属性,将所有的属性以及对应的值放在一个字典中传给attrs属性。
    2. 有些时候,在提取标签的时候,不想提取那么多,那么可以使用limit参数。限制提取多少个。

    find与find_all的区别:

    1. find:找到第一个满足条件的标签就返回。说白了,就是只会返回一个元素。
    2. find_all:将所有满足条件的标签都返回。说白了,会返回很多标签(以列表的形式)。

    使用find和find_all的过滤条件:

    1. 关键字参数:将属性的名字作为关键字参数的名字,以及属性的值作为关键字参数的值进行过滤。
    2. attrs参数:将属性条件放到一个字典中,传给attrs参数。

    获取标签的属性:

    1. 通过下标获取:通过标签的下标的方式。
       href = a['href']
    
    1. 通过attrs属性获取:示例代码:
       href = a.attrs['href']
    

    CSS选择器:

    select方法:

    使用以上方法可以方便的找出元素。但有时候使用css选择器的方式可以更加的方便。使用css选择器的语法,应该使用select方法。以下列出几种常用的css选择器方法:

    (1)通过标签名查找:

    print(soup.select('a'))
    

    (2)通过类名查找:

    通过类名,则应该在类的前面加一个.。比如要查找class=sister的标签。示例代码如下:

    print(soup.select('.sister'))
    

    (3)通过id查找:

    通过id查找,应该在id的名字前面加一个#号。示例代码如下:

    print(soup.select("#link1"))
    

    (4)组合查找:

    组合查找即和写 class 文件时,标签名与类名、id名进行的组合原理是一样的,例如查找 p 标签中,id 等于 link1的内容,二者需要用空格分开:

    print(soup.select("p #link1"))
    

    直接子标签查找,则使用 > 分隔:

    print(soup.select("head > title"))
    

    (5)通过属性查找:

    查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。示例代码如下:

    print(soup.select('a[href="http://example.com/elsie"]'))
    

    (6)获取内容

    以上的 select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容。

    soup = BeautifulSoup(html, 'lxml')
    print(type(soup.select('title')))
    print(soup.select('title')[0].get_text())
    for title in soup.select('title'):
        print(title.get_text())
    

    正则表达式:

    单字符匹配:

    # 匹配某个字符串:
    # text = "abc"
    # ret = re.match('b',text)
    # print(ret.group())
    
    
    # 点(.):匹配任意的字符(除了'\n'):
    # text = "\nabc"
    # ret = re.match('.',text)
    # print(ret.group())
    
    
    # \d:匹配任意的数字:
    # text = "aab"
    # ret = re.match('\d',text)
    # print(ret.group())
    
    
    # \D:匹配任意的非数字:
    # text = "cab"
    # ret = re.match('\D',text)
    # print(ret.group())
    
    
    # \s:匹配的是空白字符(包括:\n,\t,\r和空格):
    # text = " ab"
    # ret = re.match('\s',text)
    # print("="*30)
    # print(ret.group())
    # print("="*30)
    
    
    # \S:非空白字符:
    # text = "\nab"
    # ret = re.match('\S',text)
    # print("="*30)
    # print(ret.group())
    # print("="*30)
    
    
    # \w:匹配的是a-z和A-Z以及数字和下划线:
    # text = "+bc"
    # ret = re.match('\w',text)
    # print("="*30)
    # print(ret.group())
    # print("="*30)
    
    
    # \W:匹配的是和\w相反的:
    # text = "1bc"
    # ret = re.match('\W',text)
    # print("="*30)
    # print(ret.group())
    # print("="*30)
    
    
    # []组合的方式,只要满足中括号中的某一项都算匹配成功:
    # text = "bc"
    # ret = re.match('[1b]',text)
    # print("="*30)
    # print(ret.group())
    # print("="*30)
    
    # 使用组合的方式[0-9]\d:
    # text = "abc"
    # ret = re.match('[^0-9]',text)
    # print("="*30)
    # print(ret.group())
    # print("="*30)
    
    # 使用组合的方式实现\w:
    text = "+bc"
    ret = re.match('[^a-zA-Z0-9_]',text)
    print("="*30)
    print(ret.group())
    print("="*30)
    

    多字符匹配:

    # *:匹配0个或者多个字符:
    # text = "+abc"
    # result = re.match('\D*',text)
    # print(result.group())
    
    
    # +:匹配1个或者多个字符:
    # text = "1abc"
    # result = re.match('\w+',text)
    # print(result.group())
    
    
    # ?:匹配前一个字符0个或者1个:
    # text = "+abc"
    # result = re.match('\w?',text)
    # print(result.group())
    
    
    # {m}:匹配m个字符:
    # text = "+1abc"
    # result = re.match('\w{2}',text)
    # print(result.group())
    
    
    # {m,n}:匹配m-n之间的个数的字符:
    text = "1abc+"
    result = re.match('\w{1,3}',text)
    print(result.group())
    

    正则表达式案例:

    # 1. 验证手机号码:手机号码的规则是以1开头,第二位可以是34587,后面那9位就可以随意了。
    # text = "18677889900"
    # result = re.match("1[34587]\d{9}",text)
    # print(result.group())
    
    
    # 2. 验证邮箱:邮箱的规则是邮箱名称是用数字、英文字符、下划线组成的,然后是@符号,后面就是域名了。
    # text = "[email protected]"
    # result = re.match("\w+@[a-z0-9]+\.[a-z]+",text)
    # print(result.group())
    
    
    # 3. 验证URL:URL的规则是前面是http或者https或者是ftp然后再加上一个冒号,再加上一个斜杠,再后面就是可以出现任意非空白字符了。
    # text = "https://baike.baidu.com/item/Python/407313?fr=aladdin"
    # result = re.match("(http|https|ftp)://\S+",text)
    # print(result.group())
    
    
    # 4. 验证身份证:身份证的规则是,总共有18位,前面17位都是数字,后面一位可以是数字,也可以是小写的x,也可以是大写的X。
    text = "36530019870716234x"
    result = re.match("\d{17}[\dxX]",text)
    print(result.group())
    

    开始/结束/贪婪和非贪婪:

    # ^:以...开头:
    # text = "hello world"
    # result = re.search("world",text)
    # print(result.group())
    
    
    # $:以...结尾:
    # text = "hello world"
    # result = re.search("hello$",text)
    # print(result.group())
    # text = ""
    # result = re.search("^$",text)
    # print(result.group())
    
    
    # |:匹配多个字符串或者表达式:
    
    
    
    # 贪婪和非贪婪:
    # text = "12345"
    # result = re.search("\d+?",text)
    # print(result.group())
    
    
    # 案例1:提取html标签名称:
    # text = "

    这是标题

    "
    # result = re.search("<.+?>",text) # print(result.group()) # 案例2:验证一个字符是不是0-100之间的数字: # 0,1,99,100 # 01 text = "101" result = re.match("0$|[1-9]\d?$|100$",text) print(result.group())

    转义字符和原生字符串:

    # Python中的转义字符:
    # raw
    # text = r"hello\nworld"
    # print(text)
    
    
    # 正则表达式中的转义字符:
    # text = "apple price is $99,range price is $88"
    # result = re.findall("\$\d+",text)
    # print(result)
    
    
    # 原生字符串和正则表达式:
    # 正则表达式的字符串解析规则:
    # 1. 先把这个字符串放在Python语言层面进行解析。
    # 2. 把Python语言层面解析的结果再放到正则表达式层间进行解析。
    text = "\cba c"
    # result = re.match("\\\\c",text) # \\\\c =(Python语言层面)> \\c =(正则表达式层面)> \c
    result = re.match(r"\\c",text) # \\c =(正则表达式层面)> \c
    print(result.group())
    

    分组:

    text = "apple price is $99,orange price is $88"
    result = re.search('.+(\$\d+).+(\$\d+)',text)
    print(result.groups())
    
    # group()/group(0):匹配整个分组
    # group(1):匹配第一个分组
    # group(2):匹配第二个分组
    # groups():获取所有的分组
    

    re中常用的函数:

    # findall:查找所有满足条件的
    # text = "apple price is $99,orange price is $88"
    # result = re.findall(r'\$\d+',text)
    # print(result)
    
    # sub:根据规则替换其他字符串
    # text = "nihao zhongguo,hello world"
    # new_text = text.replace(" ","\n")
    # new_text = re.sub(r' |,','\n',text)
    # print(new_text)
    # html = """
    # 
    #

    1. 3年以上相关开发经验 ,全日制统招本科以上学历

    #

    2. 精通一门或多门开发语言(Python,C,Java等),其中至少有一门有3年以上使用经验

    #

    3. 熟练使用ES/mysql/mongodb/redis等数据库;

    #

    4. 熟练使用django、tornado等web框架,具备独立开发 Python/Java 后端开发经验;

    #

    5. 熟悉 Linux / Unix 操作系统 

    #

    6. 熟悉 TCP/IP,http等网络协议

    #

    福利:

    #

    1、入职购买六险一金(一档医疗+公司全额购买商业险)+开门红+全额年终奖(1年13薪,一般会比一个月高)

    #

    2、入职满一年有2次调薪调级机会

    #

    3、项目稳定、团队稳定性高,团队氛围非常好(汇合员工占招行总员工比例接近50%);

    #

    4、有机会转为招商银行内部员工;

    #

    5、团队每月有自己的活动经费,法定节假日放假安排;

    #

    6、办公环境优良,加班有加班费(全额工资为计算基数,加班不超过晚上10点,平日加班为时薪1.5倍,周末加班为日薪2倍,周末加班也可优先选择调休,管理人性化)。

    #
    # """ # new_html = re.sub(r'<.+?>',"",html) # print(new_html) # split:根据规则分割字符串 # text = "nihao zhongguo,hello world" # result = re.split(r' |,',text) # print(result) # compile:编译正则表达式 text = "apple price is 34.56" # r = re.compile(r""" # \d+ # 整数部分 # \.? # 小数点 # \d* # 小数部分 # """,re.VERBOSE) # result = re.search(r,text) result = re.search(r""" \d+ # 整数部分 \.? # 小数点 \d* # 小数部分 """,text,re.VERBOSE) print(result.group())

    如果想要在正则表达式中加注释,那么需要在正则表达式的函数最后加一个re.VERBOSE

    你可能感兴趣的:(阿当学Python,python)