zoukankan      html  css  js  c++  java
  • 爬虫之xpath、bs4

    • 常用xpath表达式回顾
    属性定位:
        #找到class属性值为song的div标签
        //div[@class="song"] 
    层级&索引定位:
        #找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
        //div[@class="tang"]/ul/li[2]/a
    逻辑运算:
        #找到href属性值为空且class属性值为du的a标签
        //a[@href="" and @class="du"]
    模糊匹配:
        //div[contains(@class, "ng")]
        //div[starts-with(@class, "ta")]
    取文本:
        # /表示获取某个标签下的文本内容
        # //表示获取某个标签下的文本内容和所有子标签下的文本内容
        //div[@class="song"]/p[1]/text()
        //div[@class="tang"]//text()
    取属性:
        //div[@class="tang"]//li[2]/a/@href
    • 代码中使用xpath表达式进行数据解析:
    1.下载:pip install lxml
    2.导包:from lxml import etree
    
    3.将html文档或者xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点
    
      2.1 本地文件:tree = etree.parse(文件名)
                    tree.xpath("xpath表达式")
    
      2.2 网络数据:tree = etree.HTML(网页内容字符串)
                    tree.xpath("xpath表达式")
    • 安装xpath插件在浏览器中对xpath表达式进行验证:可以在插件中直接执行xpath表达式
      • 将xpath插件拖动到谷歌浏览器拓展程序(更多工具)中,安装成功

      • 启动和关闭插件 ctrl + shift + x

    • 项目需求:获取好段子中段子的内容和作者   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)

    用xpath爬取小说《三国演义》实例:

     1 from lxml import etree
     2 import requests
     3 
     4 url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
     5 headers = {
     6 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36",
     7 "Connection":"close"
     8 }
     9 url_content = requests.get(url=url,headers=headers).text
    10 
    11 tree = etree.HTML(url_content)
    12 href_list = tree.xpath('//div[@class="book-mulu"]//li/a/@href')
    13 new_url = 'http://www.shicimingju.com'
    14 print("开始")
    15 with open('./sanguo_xpath.txt','w',encoding='utf-8') as fp:
    16     for href in href_list:
    17         zhangjie_url = new_url + href
    18         url_zhangjie = requests.get(url=zhangjie_url,headers=headers).text
    19         zhangjie_tree = etree.HTML(url_zhangjie)
    20         content_title = zhangjie_tree.xpath('//div[@class="www-main-container www-shadow-card "]/h1/text()')[0]
    21         content = "".join(zhangjie_tree.xpath('//div[@class="chapter_content"]//text()'))
    22         fp.write(content_title+"
    "+content+"
    ")
    23 print("结束")

    【重点】

        - 问题:往往在进行大量请求发送的时候,经常会报出这一样的一个错误:HTTPConnectionPool(host:XX)Max retries exceeded with url。

        - 原因:

            1.每次数据传输前客户端要和服务器建立TCP连接,为节省传输消耗,默认为keep-alive,即连接一次,传输多次。然而如果连接迟迟不断开的话,则连接池满后则无法产生新的链接对象,导致请求无法发送。

            2.ip被封

            3.请求频率太频繁

        - 解决:如果下列解决未生效,则可以尝试再次执行程序

            1.设置请求头中的Connection的值为close,表示每次请求成功后断开连接

            2.更换请求ip

            3.每次请求之间使用sleep进行等待间隔

    import requests
    from fake_useragent import UserAgent
    from lxml import etree
    import random
    import time
    
    url = 'http://sc.chinaz.com/jianli/free_%d.html'
    ua = UserAgent(verify_ssl=False,use_cache_server=False).random
    headers = {
        'User-Agent':ua,
        #保证http请求成功后,立即断开连接,以解决HTTPConnectionPool(host:XX)Max retries exceeded with url的问题
        'Connection': 'close', #该行不写,则会报错
    }
    #proxy_list = ['101.255.56.201:36501','39.137.69.10:8080','195.29.106.178:58292','120.76.77.152:9999','178.75.1.111:50411','78.156.225.170:41258','193.192.177.196:56480']
    for pageNum in range(1,3):
        get_url = format(url%pageNum)
        if pageNum==1:
            get_url = 'http://sc.chinaz.com/jianli/free.html'
        response = requests.get(url=get_url,headers=headers)
        response.encoding = 'utf-8'#处理中文乱码问题
        page_text = response.text
        tree = etree.HTML(page_text)
        div_list = tree.xpath('//div[@id="container"]/div')
        for div in div_list:
            second_url = div.xpath('./a/@href')[0]
            name = div.xpath('./p/a/text()')[0]+'.rar'
            second_page_text = requests.get(url=second_url,headers=headers).text
            second_tree = etree.HTML(second_page_text)
            download_url_list = second_tree.xpath('//div[@class="clearfix mt20 downlist"]/ul/li/a/@href')
            download_url = random.choice(download_url_list)
            data = requests.get(url=download_url,headers=headers).content
            with open(name,'wb') as fp:
                fp.write(data)
                print('下载完毕===>'+name)
    
    #解决HTTPConnectionPool(host:XX)Max retries exceeded with url的问题:
            #time.sleep(3) #延长请求时间,模拟浏览器,否则请求频率太快会请求失败
            #使用代理池
            #设置请求头信息中的Connection为close


    .BeautifulSoup解析

    • 环境安装
    - 需要将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文件中的内容
    
    基础巩固:
        (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爬取《三国演义》代码:

     1 from bs4 import BeautifulSoup
     2 import  requests
     3 
     4 headers = {
     5 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36",
     6 "Connection":"close"
     7 }
     8 url = "http://www.shicimingju.com/book/sanguoyanyi.html"
     9 
    10 def get_content(content_url):
    11     new_url= "http://www.shicimingju.com"
    12     get_cont_url = new_url + content_url
    13     print(get_cont_url)
    14     res = requests.get(url=get_cont_url,headers=headers).text
    15     new_bs4_obj = BeautifulSoup(res,'lxml')
    16     ele = new_bs4_obj.find('div',class_='chapter_content')
    17     content = ele.text
    18     return content
    19 
    20 response = requests.get(url=url, headers=headers)
    21 res_text = response.text
    22 bs4_obj = BeautifulSoup(res_text,'lxml')
    23 a_elements = bs4_obj.select('.book-mulu > ul > li > a')
    24 print(a_elements)
    25 with open('./sanguo_bs4.txt','w',encoding='utf-8') as fp:
    26     print("开始")
    27     for a_element in a_elements:
    28         title = a_element.text
    29         content_url = a_element['href']
    30         print(title)
    31         print(content_url)
    32         content = get_content(content_url)
    33         fp.write(title + "
    " + content +"
    ")
    34 print("结束")

      

  • 相关阅读:
    86. 分隔链表
    85. 最大矩形
    84. 柱状图中最大的矩形
    82. 删除排序链表中的重复元素 II
    80. 删除排序数组中的重复项 II
    77. 组合
    java-xml
    java-反射
    springboot解决跨域问题(CorsConfig )
    解决oracle锁表
  • 原文地址:https://www.cnblogs.com/zhaosijia/p/10133880.html
Copyright © 2011-2022 走看看