zoukankan      html  css  js  c++  java
  • python爬虫之数据的三种解析方式

    一、正则解析

    单字符:
            . : 除换行以外所有字符
            [] :[aoe] [a-w] 匹配集合中任意一个字符
            d :数字  [0-9]
            D : 非数字
            w :数字、字母、下划线、中文
            W : 非w
            s :所有的空白字符包,括空格、制表符、换页符等等。等价于 [ f
    
    	v]。
            S : 非空白
        数量修饰:
            * : 任意多次  >=0
            + : 至少1次   >=1
            ? : 可有可无  0次或者1次
            {m} :固定m次 hello{3,}
            {m,} :至少m次
            {m,n} :m-n次
        边界:
            $ : 以某某结尾 
            ^ : 以某某开头
        分组:
            (ab)  
        贪婪模式 .*
        非贪婪(惰性)模式 .*?
    
        re.I : 忽略大小写
        re.M :多行匹配
        re.S :单行匹配
    
        re.sub(正则表达式, 替换内容, 字符串)

    正则练习

    import re
    #提取出python
    key="javapythonc++php"
    pl='python' #正则表达式
    re.findall(pl,key) #findall返回的是一个列表
    #提取出hello world
    key="<html><h1>hello world<h1></html>"
    pl='<h1>(.*)<h1>'
    re.findall(pl,key)[0]
    #提取170
    string = '我喜欢身高为170的女孩'
    pl='d+'
    re.findall(pl,string)[0]
    #提取出http://和https://
    key='http://www.baidu.com and https://boob.com'
    pl='https*://'          #*号前的s出现零次或任意次
    re.findall(pl,key)
    #提取出hello
    key='lalala<hTml>hello</HtMl>hahah' #输出<hTml>hello</HtMl>
    pl='<[hH][tT][mM][lL]>(.*)</[hH][tT][mM][lL]>'        #[]是匹配中括号中的任意一个字符
    re.findall(pl,key)[0]
    #提取出hit :贪婪模式:尽可能多的匹配数据
    key='bobo@hit.edu.com'#想要匹配到hit.
    pl='h.*.'            #贪婪匹配的结果是['hit.edu.'],我们应该使用非贪婪匹配,这样匹配的更精确
    re.findall(pl,key)
    #加问号的是非贪婪匹配
    key='bobo@hit.edu.com'#想要匹配到hit.
    pl='h.*?.'       #此时匹配的结果是['hit.']
    re.findall(pl,key)
    #{a,b}表示其前一个字符或者表达式可以重复的范围是 a<=次数<=b
    key='saas and sas and saaas'#匹配sas和saas
    pl='sa{1,2}s'         #a出现1次或2次
    re.findall(pl,key)
    #匹配出i开头的行
    string = '''fall in love with you
    i love you very much
    i love she
    i love her'''
    
    pl='^i.*'
    #re.M或者re.S或者re.I只可以作为compile函数的第二个参数
    pa=re.compile(pl,re.M)     #M是匹配多行
    pa.findall(string)
    #匹配全部行
    string1 = """<div>静夜思
    窗前明月光
    疑是地上霜
    举头望明月
    低头思故乡
    </div>"""
    
    pl='<div>(.*)</div>'
    pa=re.compile(pl,re.S)
    pa.findall(string1)

    -综合练习:

        需求:爬取糗事百科指定页面的糗图,并将其保存到指定文件夹中

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import requests
    import re
    import os
    if __name__ == "__main__":
         url = 'https://www.qiushibaike.com/pic/%s/'
         headers={
             'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
         }
         #指定起始也结束页码
         page_start = int(input('enter start page:'))
         page_end = int(input('enter end page:'))
    
         #创建文件夹
         if not os.path.exists('images'):
             os.mkdir('images')
         #循环解析且下载指定页码中的图片数据
         for page in range(page_start,page_end+1):
             print('正在下载第%d页图片'%page)
             new_url = format(url % page)
             response = requests.get(url=new_url,headers=headers)
    
             #解析response中的图片链接
             e = '<div class="thumb">.*?<img src="(.*?)".*?>.*?</div>'
             pa = re.compile(e,re.S)
             image_urls = pa.findall(response.text)
              #循环下载该页码下所有的图片数据
             for image_url in image_urls:
                 image_url = 'https:' + image_url
                 image_name = image_url.split('/')[-1]
                 image_path = 'images/'+image_name
    
                 image_data = requests.get(url=image_url,headers=headers).content
                 with open(image_path,'wb') as fp:
                     fp.write(image_data)

    二.bs4解析

    - 环境安装:

    - 需要将pip源设置为国内源,阿里源、豆瓣源、网易源等
       - windows
        (1)打开文件资源管理器(文件夹地址栏中)
        (2)地址栏上面输入 %appdata%3)在这里面新建一个文件夹  pip
        (4)在pip文件夹里面新建一个文件叫做  pip.ini ,内容写如下即可
            [global]
            timeout = 6000
            index-url = https://mirrors.aliyun.com/pypi/simple/
            trusted-host = mirrors.aliyun.com
       - linux
        (1)cd ~2)mkdir ~/.pip
        (3)vi ~/.pip/pip.conf
        (4)编辑内容,和windows一模一样
      - 需要安装:pip install bs4
        bs4在使用时候需要一个第三方库,把这个库也安装一下
        pip install lxml

    - 简单使用规则:

    - from bs4 import BeautifulSoup
            - 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的内容1)转化本地文件:
                  - soup = BeautifulSoup(open('本地文件'), 'lxml')
              (2)转化网络文件:
                  - soup = BeautifulSoup('字符串类型或者字节类型', 'lxml')
              (3)打印soup对象显示内容为html文件中的内容
       以下是对soup对象的一些常见操作:
    1)根据标签名查找 - soup.a 只能找到第一个符合要求的标签 (2)获取属性 - soup.a.attrs 获取a所有的属性和属性值,返回一个字典 - soup.a.attrs['href'] 获取href属性 - soup.a['href'] 也可简写为这种形式 (3)获取内容 - soup.a.string - soup.a.text - soup.a.get_text() 【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容 (4)find:找到第一个符合要求的标签 - soup.find('a') 找到第一个符合要求的 - soup.find('a', title="xxx") - soup.find('a', alt="xxx") - soup.find('a', class_="xxx") - soup.find('a', id="xxx") (5)find_all:找到所有符合要求的标签 - soup.find_all('a') - soup.find_all(['a','b']) 找到所有的a和b标签 - soup.find_all('a', limit=2) 限制前两个 (6)select:soup.select('#feng') - 根据选择器选择指定的内容 - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器 - 层级选择器: div .dudu #lala .meme .xixi 下面好多级 div > p > a > .lala 只能是下面一级 【注意】select选择器返回永远是列表,需要通过下标提取指定的对象

    - 综合练习:

        需求:使用bs4实现将诗词名句网站中三国演义小说的每一章的内容爬去到本地磁盘进行存储   http://www.shicimingju.com/book/sanguoyanyi.html

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import requests
    from bs4 import BeautifulSoup
    
    headers={
             'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
         }
    def parse_content(url):
        #获取标题正文页数据
        page_text = requests.get(url,headers=headers).text
        soup = BeautifulSoup(page_text,'lxml')
        #解析获得标签
        ele = soup.find('div',class_='chapter_content')
        content = ele.text #获取标签中的数据值
        return content
    
    if __name__ == "__main__":
         url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
         reponse = requests.get(url=url,headers=headers)
         page_text = reponse.text
    
         #创建soup对象
         soup = BeautifulSoup(page_text,'lxml')
         #解析数据
         a_eles = soup.select('.book-mulu > ul > li > a')
         print(a_eles)
         cap = 1
         for ele in a_eles:
             print('开始下载第%d章节'%cap)
             cap+=1
             title = ele.string
             content_url = 'http://www.shicimingju.com'+ele['href']
             content = parse_content(content_url)
    
             with open('./sanguo.txt','w') as fp:
                 fp.write(title+":"+content+'
    
    
    
    
    ')
                 print('结束下载第%d章节'%cap)

    三.xpath解析

    from lxml import etree
        两种方式使用:将html文档变成一个对象,然后调用对象的方法去查找指定的节点
        (1)本地文件
            tree = etree.parse(文件名)
        (2)网络文件
            tree = etree.HTML(网页字符串)
    
        ret = tree.xpath(路径表达式)
        【注】ret是一个列表

      参考文献:http://www.w3school.com.cn/xpath/xpath_intro.asp

      - 安装xpath插件:可以在插件中直接执行xpath表达式

        1.将xpath插件拖动到谷歌浏览器拓展程序(更多工具)中,安装成功

        2.启动和关闭插件 ctrl + shift + x

     - 常用表达式:

    /bookstore/book           选取根节点bookstore下面所有直接子节点book
        //book                    选取所有book
        /bookstore//book          查找bookstore下面所有的book
        /bookstore/book[1]        bookstore里面的第一个book
        /bookstore/book[last()]   bookstore里面的最后一个book
        /bookstore/book[position()<3]  前两个book
        //title[@lang]            所有的带有lang属性的title节点
        //title[@lang='eng']      所有的lang属性值为eng的title节点
        属性定位
                //li[@id="hua"]
                //div[@class="song"]
        层级定位&索引
                //div[@id="head"]/div/div[2]/a[@class="toindex"]
                【注】索引从1开始
                //div[@id="head"]//a[@class="toindex"]
                【注】双斜杠代表下面所有的a节点,不管位置
         逻辑运算
                //input[@class="s_ipt" and @name="wd"]
         模糊匹配 :
              contains
                    //input[contains(@class, "s_i")]
                    所有的input,有class属性,并且属性中带有s_i的节点
                    //input[contains(text(), "")]
                starts-with
                    //input[starts-with(@class, "s")]
                    所有的input,有class属性,并且属性以s开头
          取文本
                //div[@id="u1"]/a[5]/text()  获取节点内容
                //div[@id="u1"]//text()      获取节点里面不带标签的所有内容
          取属性
                //div[@id="u1"]/a[5]/@href

    - 代码中使用xpath:

        1.导包:from lxml import etree

        2.将html文档或者xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点

          2.1 本地文件:tree = etree.parse(文件名)

          2.2 网络数据:tree = etree.HTML(网页内容字符串)

    - 综合练习:

        需求:获取好段子中段子的内容和作者   http://www.haoduanzi.com

    from lxml import etree
    import requests
    
    url='http://www.haoduanzi.com/category-10_2.html'
    headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
        }
    url_content=requests.get(url,headers=headers).text
    #使用xpath对url_conten进行解析
    #使用xpath解析从网络上获取的数据
    tree=etree.HTML(url_content)
    #解析获取当页所有段子的标题
    title_list=tree.xpath('//div[@class="log cate10 auth1"]/h3/a/text()')
    
    ele_div_list=tree.xpath('//div[@class="log cate10 auth1"]')
    
    text_list=[] #最终会存储12个段子的文本内容
    for ele in ele_div_list:
        #段子的文本内容(是存放在list列表中)
        text_list=ele.xpath('./div[@class="cont"]//text()')
        #list列表中的文本内容全部提取到一个字符串中
        text_str=str(text_list)
        #字符串形式的文本内容防止到all_text列表中
        text_list.append(text_str)
    print(title_list)
    print(text_list)
  • 相关阅读:
    20160402_[转]联合体(union)的使用方法及其本质
    20160402_C语言位操作符的使用
    20160402_多道程序环境中的设备抢占问题
    20160402_TCP/IP协议簇
    20160402_TCP连接的建立、终止和状态转换
    20160402_C++中的内存对齐
    20160127_Android程序完全退出的方法
    Redis持久化
    github慢!怎么办?
    mybatis-plus-generator: 自动生成entity,mapper,service,controller的代码
  • 原文地址:https://www.cnblogs.com/sui776265233/p/9709710.html
Copyright © 2011-2022 走看看