zoukankan      html  css  js  c++  java
  • Python urllib与requests、XML和HTMLParser

    参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1019223241745024

    Python 的内建模块urllib提供了一系列用于操作url的方法

      Get

      urllib的request可以非常方便的抓取URL的内容,通过GET发送一个请求到指定页面,然后返回HTTP响应

      还可以模仿浏览器发送一个GET请求,需要request对象,通过向request对象中添加HTTP请求头,就可以把请求伪装为一个浏览器

      Post

      需要把参数以bytes类型传入

      Handler

      如果还需要更复杂的控制,加入需要通过一个代理去登陆网站,需要使用proxyhandler模块

      urllib提供的功能就是通过程序完成各种各样的HTTP请求,如果需要模仿浏览器完成特定功能,需要将请求伪装为浏览器请求,伪装的方法是先监控浏览器发出的请求,然后再根据浏览器的请求头来伪装,User-Agent头就是用来识别浏览器的

    requests

      requests是用于操作URl的第三方模块,相比Python提供的内建模块urllib,此模块使用起来更方便

      参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1183249464292448

      使用GET访问一个页面

        使用params参数传入一个dict类型的参数做为访问url的参数

      使用headers参数,传入一个dict类型的参数作为请求头

      requests默认使用application/x-www-form-urlencoded对POST数据编码。如果要传递JSON数据,可以直接传给json参数

    params = {'key': 'value'}
    r = requests.post(url, json=params) # 内部自动序列化为JSON
    

      如果需要上传文件,可以直接将一个file对象传给files参数

    >>> upload_files = {'file': open('report.xls', 'rb')}
    >>> r = requests.post(url, files=upload_files)

      在读取文件时,注意务必使用'rb'即二进制模式读取,这样获取的bytes长度才是文件的长度。

      把post()方法替换为put()delete()等,就可以以PUT或DELETE方式请求资源。

      除了能轻松获取响应内容外,requests对获取HTTP响应的其他信息也非常简单。

      例如,获取响应头

    >>> r.headers
    {Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Content-Encoding': 'gzip', ...}
    >>> r.headers['Content-Type']
    'text/html; charset=utf-8'
    

      

      requests对Cookie做了特殊处理,使得我们不必解析Cookie就可以轻松获取指定的Cookie

    >>> r.cookies['ts']
    'example_cookie_12345'
    

      要在请求中传入Cookie,只需准备一个dict传入cookies参数

      可以使用encoding属性查看编码

      无论响应的内容是文本或者二进制文件,都可以使用content属性获取其bytes对象

      如果响应的是特定的类型,比如Json,可以使用json()方法直接获取

      最后,要指定超时,传入以秒为单位的timeout参数:

    >>> r = requests.get(url, timeout=2.5) # 2.5秒后超时
    

      

    XML

      参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017784095418144

      操作XML有两种方法:DOM和SAX。DOM会把整个XML读入内存,解析为树,因此占用内存大,解析慢,优点是可以任意遍历树的节点。SAX是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自己处理事件。

      正常情况下,优先考虑SAX,因为DOM实在太占内存。

      注意使用attrs这个值

      当SAX解析器读到一个节点时:

    <a href="/">python</a>
    

      

      会产生3个事件:

    1. start_element事件,在读取<a href="/">时;

    2. char_data事件,在读取python时;

    3. end_element事件,在读取</a>时。

      什么是事件呢?

    from xml.parsers.expat import ParserCreate
    class DefaultSaxHandler(object):
        def start_element(self,name,attrs):
            print('sax:start_element:%s,attrs:%s'%(name,str(attrs)))#这里可以写 当读到这里时要发生的事件
        def end_element(self,name):
            print('sax:end_element:%s'%name)#这里可以写 当读到这里时要发生的事件
        def char_data(self,text):
            print('sax:char_data:%s'%text)#这里可以写 当读到这里时要发生的事件
    xml = r'''<?xml version="1.0"?>
    <ol>
        <li><a href="/python">Python</a></li>
        <li><a href="/ruby">Ruby</a></li>
    </ol>
    '''
    handler=DefaultSaxHandler()
    parser=ParserCreate()
    parser.StartElementHandler=handler.start_element
    parser.EndElementHandler=handler.end_element
    parser.CharacterDataHandler=handler.char_data
    parser.Parse(xml)
    #输出
    sax:start_element:ol,attrs:{}
    sax:char_data:
    
    sax:char_data:
    sax:start_element:li,attrs:{}
    sax:start_element:a,attrs:{'href': '/python'}
    sax:char_data:Python
    sax:end_element:a
    sax:end_element:li
    sax:char_data:
    
    sax:char_data:
    sax:start_element:li,attrs:{}
    sax:start_element:a,attrs:{'href': '/ruby'}
    sax:char_data:Ruby
    sax:end_element:a
    sax:end_element:li
    sax:char_data:
    
    sax:end_element:ol
    

      需要注意的是读取一大段字符串时,CharacterDataHandler可能被多次调用,所以需要自己保存起来,在EndElementHandler里面再合并。

      除了解析XML外,如何生成XML呢?99%的情况下需要生成的XML结构都是非常简单的,因此,最简单也是最有效的生成XML的方法是拼接字符串:

      如果要生成复杂的XML呢?建议你不要用XML,改成JSON。

      解析XML时,注意找出自己感兴趣的节点,响应事件时,把节点数据保存起来。解析完毕后,就可以处理数据。

      比如可以解析XML数据获得相关城市的天气信息(略)

    HTMLParser

      参考链接:https://www.liaoxuefeng.com/wiki/1016959663602400/1017784593019776

      当我们爬取了网页,下一步就是解析HTML页面,看看里面的内容,到底是图片、视频还是文本。

      利用HTMLParser,可以把网页中的文本、图像等解析出来。

      HTML本质上是XML的子集,但是语法没有XML要求的那么严格,所以不能通过标准的DOM或者SAX来解析HTML

      好在Python提供了HTMLParser来非常方便地解析HTML,只需简单几行代码:

      注意使用attrs这个值,可以用来抽取链接、识别id为某个值元素

    from html.parser import HTMLParser
    from html.entities import name2codepoint
    
    class MyHTMLParser(HTMLParser):
    
        def handle_starttag(self, tag, attrs):
            print('<%s>' % tag)
    
        def handle_endtag(self, tag):
            print('</%s>' % tag)
    
        def handle_startendtag(self, tag, attrs):
            print('<%s/>' % tag)#如img标签<img src="",alt=""/>
    
        def handle_data(self, data):
            print(data)
    
        def handle_comment(self, data):
            print('<!--', data, '-->')
    
        def handle_entityref(self, name):#解析特殊字符
            print('&%s;' % name)
    
        def handle_charref(self, name):#解析特殊字符
            print('&#%s;' % name)
    
    parser = MyHTMLParser()
    parser.feed('''<html>
    <head></head>
    <body>
    <!-- test html parser -->
        <p>Some <a href="#">html</a> HTML tutorial...<br>END</p>
    </body></html>''')
    #输出
    (sort) λ python fortest.py
    <html>
    
    
    <head>
    </head>
    
    
    <body>
    
    
    <!--  test html parser  -->
    
    
    <p>
    Some
    <a>
    html
    </a>
     HTML tutorial...
    <br>
    END
    </p>
    
    
    </body>
    </html>
    

      feed()方法可以多次调用,也就是不一定一次把整个HTML字符串都塞进去,可以一部分一部分塞进去。

      可是这样怎么识别有特定id的标签呢?,注意使用attrs这个值

    def find_id(self,id_name,attrs):
            for i in attrs:
                if id_name in i:
                    return True
            return False
    
        def handle_starttag(self, tag, attrs):
            if self.find_id('test1',attrs):
                print('<%s%s>' %(tag,str(attrs)))
        pass
        
        parser.feed('''<html>
    <head></head>
    <body>
    <!-- test html parser -->
        <p class='test' id='test1'>Some <a href="#">html</a> HTML tutorial...<br>END</p>
    </body></html>''')
       
    #输出
    pass
    <p[('class', 'test'), ('id', 'test1')]>
    pass
    

      

      特殊字符有两种,一种是英文表示的&nbsp;,一种是数字表示的&#1234;,这两种字符都可以通过Parser解析出来。

  • 相关阅读:
    怎么将ETL技术落地
    vue.js解决刷新404找不到页面问题
    Python 图像识别入门篇
    快速实现CentOS7安装python-pip
    ffmpeg+HLS实现直播与回放
    HBase 二级索引与Coprocessor协处理器
    你做电商死法TOP10:你中了几枪?
    讲讲跳跃表(Skip Lists)
    说框架设计思路
    《Effective Java 第三版》目录汇总
  • 原文地址:https://www.cnblogs.com/Gaoqiking/p/11618646.html
Copyright © 2011-2022 走看看