zoukankan      html  css  js  c++  java
  • 爬虫 正则 bs4 xpath 中文乱码 管道符

    爬虫的分类:
    通用:
    聚焦:数据解析
    增量式:监测
    http:客户端和服务器端进行数据交互的形式
    证书密钥加密:
    什么是证书?
    证书种包含的是经过数字签名的公钥
    反爬:
    robots
    UA伪装
    请求载体的身份标识
    在headers种应用一个字典(请求头信息:UA)
    动态加载的数据
    如何处理动态请求参数:
    封装到一个字典中,字典需要作用到data或者params
    • 编码的流程
      • 指定url
      • 发起请求
      • 获取响应数据
      • 数据解析
      • 持久化存储
    • 数据解析的作用
      • 用于获取页面中局部的页面源码数据
    • 如何实现数据解析
      • 正则
      • bs4(独有)
      • xpath(最为通用)
      • pyquery
    • 数据解析的通用原理是什么?
      • 标签定位
      • 将标签中间存储的文本数据或者其属性值进行捕获

    正则解析

    • 需求:爬取糗事百科中的图片数据
      • 确认了页面中没有动态加载数据的存在

    #爬取糗事百科
    # re正则匹配
    import requests
    import re
    import os
    headers={
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }

    dirname="./qiutu"
    # 创建文件夹
    if not os.path.exists(dirname):
    os.mkdir(dirname)


    url="https://www.qiushibaike.com/imgrank/page/%d/"

    for page in range(1,3):
    print("开始下载第{}页图片".format(page))
    #指定新的url
    new_url=format(url%page)

    #获得源码文本信息
    page_text=requests.get(url=new_url,headers=headers).text


    ex='<div class="thumb">.*?<img src="(.*?)" alt=.*?</div>'
    # 获取图片地址 注意re.S
    img_src_list=re.findall(ex,page_text,re.S)

    for img_src in img_src_list:
    new_img_src='https:'+img_src
    img_name=img_src.split("/")[-1]
    img_path=dirname+"/"+img_name
    img_text=requests.get(url=new_img_src,headers=headers).content

    with open(img_path,"wb") as f:
    f.write(img_text)
    print(img_name,"下载完毕!")

    # 方法2:
    # from urllib import request
    # request.urlretrieve(new_img_src,img_path)


    # <div class="thumb">

    # <a href="/article/121911520" target="_blank">
    # <img src="//pic.qiushibaike.com/system/pictures/12191/121911520/medium/S4TSN79VOC3G0R83.jpg" alt="糗事#121911520" class="illustration" width="100%" height="auto">
    # </a>
    # </div

    bs4解析

    • 环境的安装:
      • pip install bs4
      • pip install lxml
    • bs4解析原理
      • 实例化一个BeautifulSoup的对象,且将即将被解析的页面源码加载到该对象中
      • 使用该对象中的属性或者方法进行标签定位和数据提取
    • BeautifulSoup对象的实例化方式:lxml就是一款解析器
      • BeautifulSoup(fp,'lxml'):将本地存储的html文档加载到该对象中
      • BeautifulSoup(page_text,'lxml'):将互联网上获取的html源码加载到该对象中
    from bs4 import BeautifulSoup
    import lxml
    fp=open("./bs.html",'r',encoding="utf-8")
    soup=BeautifulSoup(fp,"lxml")
    soup
    # 标签定位
    
    # soup.tagName:返回的就是页面中第一次出现的tagName标签(返回的是一个单数)
    
    # soup.title
    # soup.div
    
    # find函数的用法:属性定位
    # soup.find('tagName',attrName='value')
    # 注意:返回的是单数
    
    soup.find('div',class_="song")
    
    
    # soup.find_all('tagName'):定位所有的tagName的标签
    # soup.find_all('tagName',attrName='value'):属性定位
    # 注意:返回值是列表
    
    # soup.find_all("div")
    # soup.find_all("div",class_="song")
    
    # select'选择器'):根据选择器进行标签定位且返回的是复数(列表)
    # 类选择器,id选择器,标签选择器,层级选择器
    # 层级选择器:>表示一个层级,空格表示多个层级
    
    # soup.select(".song > p")[0]
    # soup.select(".tang > ul > li")
    # soup.select(".tang li")
    
    
    # 取数据(属性值和标签中存储的文本数据)
    
    # text 和 string 的区别:
    #  string  获取的是标签中直系的文本内容
    #  text 获取标签中所有的文本内容
    
    
    # soup.p.string
    # soup.p.text
    
    
    # 取属性:
    # tag['attrName']
    
    
    # soup.select("div > a")[0]["href"]
    # for a in soup.select(".tang > ul > li > a"):
    #     print(a["href"])
    使用流程:       
        - 导包:from bs4 import BeautifulSoup
        - 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的节点内容
            (1)转化本地文件:
                 - soup = BeautifulSoup(open('本地文件'), 'lxml')
            (2)转化网络文件:
                 - soup = BeautifulSoup('字符串类型或者字节类型', 'lxml')
            (3)打印soup对象显示内容为html文件中的内容
    
    
    基础巩固:
        (1)根据标签名查找
            - soup.a   只能找到第一个符合要求的标签 
         - soup.div  只能找到第一个div标签
    
        (2)获取属性
            - soup.a.attrs  获取a所有的属性和属性值,返回一个字典
            - soup.a.attrs['href']   获取href属性
            - soup.a['href']   也可简写为这种形式
    
    
        (3)获取内容
            - soup.a.string   # string获取的是标签中直系的文本内容
            - soup.a.text   # text获取的是当前标签下所有文本内容,包括子标签
            - soup.a.get_text()
           【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
    
    
        (4)find:找到第一个符合要求的标签
            - soup.find('a')  找到第一个符合要求的
            - soup.find('a', title="xxx")  获取title=xxx的第一个标签
            - soup.find('a', alt="xxx")   h获取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)根据选择器选择指定的内容
                   - soup.select('#tang')
            - 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
                - 层级选择器:
                    select(".tang li") #class=tang标签下面的所有li标签,包含所有层级
                    div > p > a > .lala   # 只能是下面一级
            【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
         
         总结:层级选择器定位返回总是一个复数(列表)
     类选择器,id选择器,标签选择器,层级选择器
     层级选择器:>表示一个层级,空格表示多个层级
    爬取三国演义小说

    url
    = 'http://www.shicimingju.com/book/sanguoyanyi.html' page_text = requests.get(url=url,headers=headers).text #使用bs4进行数据解析(章节标题&内容) soup = BeautifulSoup(page_text,'lxml') a_list = soup.select('.book-mulu > ul > li > a') fp = open('sanguo.txt','w',encoding='utf-8') for a in a_list: title = a.string detail_url = 'http://www.shicimingju.com'+a['href'] #对详情页的url发起请求解析出章节内容 detail_page_text = requests.get(url=detail_url,headers=headers).text detail_soup = BeautifulSoup(detail_page_text,'lxml') content = detail_soup.find('div',class_='chapter_content').text fp.write(title+':'+content+' ') print(title,'保存成功!!!') fp.close()

    xpath

    xpath解析

    • 环境安装:pip install lxml
    • 解析原理:
      • 实例化一个etree类型的对象,且将即将被解析的页面源码数据加载到该对象中
      • 调用该对象中的xpath方法结合着不同的xpath表达式进行标签定位和数据提取
    • 实例化对象:
      • etree.parse(fileName)
      • etree.HTML(page_text)
    from lxml import etree
    tree=etree.parse('bs.html')
    
    # 属性定位
    # tree.xpath('//div[@class="song"]')
    # 索引定位
    # 索引值是从1开始
    # 在xpath表达式中非最左侧的/和//的区别?
    # /表示一个层级
    # //表示多个层级
    
    
    # tree.xpath("//div[@class='song']//text()")
    
    # 取文本
    # /text():获取的是标签下直系的文本数据
    # //text():获取的是标签下所有的文本数据
    
    # tree.xpath("//div[@class='song']/p[1]/text()")
    
    # tree.xpath("//div[@class='song']//a[1]/span/text()")
    
    # 取属性
    
    # tree.xpath("//div[@class='song']//img/@src")
    基于标签定位:
      tree.xpath('/html/head/meta')
      tree.xpath('//meta')
      xpath表达式中最左侧的/和//的区别是什么?
    /表示我们必须从根标签进行定位
    //表示我们可以从任意位置标签定位
    
    属性定位:
        #找到class属性值为song的div标签
        //div[@class="song"] 
    
    
    层级&索引定位:
        #找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
        //div[@class="tang"]/ul/li[2]/a
    
      tree.xpath('//div[@class="tang"]/ul/li[3]')  
      tree.xpath('//div[@class="tang"]//li[3]') # 与上一条属性索取为相同结果
      在xpath表达式中非最左侧的/和//的区别?
     /表示一个层级
     //表示多个层级
    
    
    逻辑运算:
        #找到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
    # 爬取boss中的岗位信息(岗位名称,薪资,公司名称,岗位描述)
    import requests
    from lxml import etree
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    
    url="https://www.zhipin.com/c101010100/?query=python后端&page=%d"
    
    fp=open("boss.txt","w",encoding="utf-8")
    
    
    for page in range(1,4):
        new_url=format(url%page)
        page_text=requests.get(url=new_url,headers=headers).text
        tree=etree.HTML(page_text)
    #     获取工作列表
        li_list=tree.xpath("//div[@class='job-box']/div[@class='job-list']/ul/li")
        
        for li in li_list:
            job_title=li.xpath("./div//h3[@class='name']/a/div[1]/text()")[0]
            salary=li.xpath("./div//h3[@class='name']/a/span/text()")[0]
            company=li.xpath("./div/div[2]/div/h3/a/text()")[0]
            
    #         详细信息网页
            detail_url='https://www.zhipin.com' + li.xpath('./div/div[1]/h3/a/@href')[0]
            detail_text=requests.get(url=detail_url,headers=headers).text
            
            detail_tree=etree.HTML(detail_text)
            desc=detail_tree.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div/text()')
            desc=''.join(desc)
            
            
            fp.write(job_title+":"+"
    "+salary+"
    "+company+"
    "+desc)
    fp.close()
    # 处理中文乱码问题
    # url = 'http://pic.netbian.com/4kmeinv/index_%d.html'
    
    import requests
    from lxml import etree
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    
    fp=open('meinv.txt','w',encoding='utf-8')
    
    
    for page in range(1,4):
        if page==1:
            url="http://pic.netbian.com/4kmeinv/"
        else:
            url="http://pic.netbian.com/4kmeinv/index_{}.html".format(page)
    
        response=requests.get(url=url,headers=headers)
        
    #     解决中文乱码方式1  耗资源 不推荐
    #     response.encoding='gbk'
        page_text=response.text
        
        tree=etree.HTML(page_text)
        li_list=tree.xpath('//*[@id="main"]/div[3]/ul/li')
        for li in li_list:
            img_name=li.xpath("./a/b/text()")[0]
            
            #     解决中文乱码方式2
            img_name=img_name.encode("iso-8859-1").decode("gbk")
            img_url='http://pic.netbian.com' +  li.xpath('./a/img/@src')[0]
            fp.write(img_name+":"+img_url+"
    ")
           
    fp.close()
       
    # 增强xpath表达式的通用性  ****采用管道符
    # url="https://www.aqistudy.cn/historydata/"
    # 获取热门城市与普通城市的城市名  
    
    import requests
    from lxml import etree
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    
    
    url="https://www.aqistudy.cn/historydata/"
    
    
    response=requests.get(url=url,headers=headers)
    page_text=response.text
    
    tree=etree.HTML(page_text)
    # hot_city=tree.xpath('//div[@class="hot"]//div[@class="bottom"]/ul/li/a/text()')
    # print(hot_city)
    # all_city=tree.xpath('//div[@class="all"]//div[@class="bottom"]/ul/div[2]/li/a/text()')
    # print(all_city)
    
    
    # cities=tree.xpath('//div[@class="hot"]//div[@class="bottom"]/ul/li/a/text() | //div[@class="all"]//div[@class="bottom"]/ul/div[2]/li/a/text()')
    # print(cities)
    
    # cities=tree.xpath('//div[@class="all"]//div[@class="bottom"]/ul/div[2]/li/a/text() | //div[@class="hot"]//div[@class="bottom"]/ul/li/a/text()')
    # print(cities)

    举例

    # 糗事百科的段子内容和作者(xpath的管道符)名称进行爬取,然后存储到mysql中or文本
    
    import requests
    from lxml import etree
    import os
    
    
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    
    dirName='./homework'
    if not os.path.exists(dirName):
        os.mkdir(dirName)
    
    filepath=os.path.join(dirName,"qiubai.txt")        
        
    fp=open(filepath,'w',encoding="utf-8")
    # 指定url
    url='https://www.qiushibaike.com/text/page/%d/'
    
    for page in range(1,10):
        print("开始下载第{}页".format(page))
        new_url=format(url%page)
        
        
    #     发送请求 获取数据
        response=requests.get(url=new_url,headers=headers)
        page_text=response.text
        tree=etree.HTML(page_text)
        info_list=tree.xpath('//div[@id="content-left"]/div')
        for info in info_list:
    #         管道符号获取所有用户
            user_name=info.xpath("./div[1]/a[2]/h2/text() | ./div[1]/span[2]/h2/text()")[0]
            
            content=info.xpath("./a[1]/div/span/text()")
            content=''.join(content)
            qiubai=user_name.strip()+":"+content.strip()+"
    
    "
            fp.write(qiubai)
    fp.close()
    print("下载完毕!")
    # http://sc.chinaz.com/jianli/free.html爬取简历模板
    
    import requests
    from lxml import etree
    import os
    import time
    import random
    
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    
    dirName='./homework'
    if not os.path.exists(dirName):
        os.mkdir(dirName)
    
        
    for page in range(1,3):
        if page==1:
            url='http://sc.chinaz.com/jianli/free.html'
        else:
            url='http://sc.chinaz.com/jianli/free_{}.html'.format(page)
        
        page_text=requests.get(url=url,headers=headers).text
        tree=etree.HTML(page_text)
        a_list=tree.xpath('//div[@id="container"]/div/a/@href')
    #     print(a_list)
    
    
        for a in a_list:
            detail_text=requests.get(url=a,headers=headers).text
            detail_tree=etree.HTML(detail_text)
            
    #         下载路径
            a_detail=detail_tree.xpath('//*[@id="down"]/div[2]/ul/li[1]/a/@href')[0]
    #         print(a_detail)
    
    
            filename=detail_tree.xpath('//div[@class="ppt_left fl"]//h1//text()')[0]
        
    #     识别中文
            filename1 = filename.encode("iso-8859-1").decode("utf-8")+'.rar'
            
            print(filename1)
            
            response=requests.get(url=a_detail,headers=headers)
            file_content=response.content
            
            filepath=os.path.join(dirName,filename1)
            print(filepath)
            with open(filepath,'wb') as f:
                f.write(file_content)
            time.sleep(random.randint(1,3))
            print("ok1111111111111")
    print("ok")
           
    
    
        
        
    开线程池
    
    
    # http://sc.chinaz.com/jianli/free.html爬取简历模板
    from concurrent.futures import ThreadPoolExecutor
    import requests
    from lxml import etree
    import os
    import time
    import random
    print("start")
    start=time.time()
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
    }
    
    dirName = './homework'
    if not os.path.exists(dirName):
        os.mkdir(dirName)
    url_dic={}
    for page in range(1, 3):
        if page == 1:
            url = 'http://sc.chinaz.com/jianli/free.html'
        else:
            url = 'http://sc.chinaz.com/jianli/free_{}.html'.format(page)
    
        page_text = requests.get(url=url, headers=headers).text
        tree = etree.HTML(page_text)
        a_list = tree.xpath('//div[@id="container"]/div/a/@href')
        #     print(a_list)
    
        for a in a_list:
            detail_text = requests.get(url=a, headers=headers).text
            detail_tree = etree.HTML(detail_text)
    
            #         下载路径
            a_detail = detail_tree.xpath('//*[@id="down"]/div[2]/ul/li[1]/a/@href')[0]
            #         print(a_detail)
    
            filename = detail_tree.xpath('//div[@class="ppt_left fl"]//h1//text()')[0]
    
            #     识别中文
            filename1 = filename.encode("iso-8859-1").decode("utf-8") + '.rar'
    
            url_dic[filename1]=a_detail
    
            # response = requests.get(url=a_detail, headers=headers)
            # file_content = response.content
            #
            # filepath = os.path.join(dirName, filename1)
            # # print(filepath)
            # with open(filepath, 'wb') as f:
            #     f.write(file_content)
            # # time.sleep(random.randint(1, 3))
    print(url_dic)
    
    
    
    
    def get_html(name,url):
        res=requests.get(url,headers=headers)
        return {"name":name,"content":res.content}
    
    def parser_page(ret_obj):
        dic=ret_obj.result()
        with open(dic['name'], 'wb') as f:
            f.write(dic['content'])
    t=ThreadPoolExecutor(30)
    
    for name in url_dic:
        task=t.submit(get_html,name,url_dic[name])
    
        task.add_done_callback(parser_page)
    
    
    
    
    
    
    print("ok",time.time()-start)
  • 相关阅读:
    2018ddctf wp
    装饰器
    python作用域
    闭包
    迭代器
    ord() expected string of length 1, but int found
    pygm2安装问题
    elf逆向入门
    【POJ
    【POJ
  • 原文地址:https://www.cnblogs.com/XLHIT/p/11297463.html
Copyright © 2011-2022 走看看