zoukankan      html  css  js  c++  java
  • Python-爬虫-基本库(urllib)使用

    urllib库的使用

    Python2中有urllib和urllib2两个内置库实现请求的发送;Python3中则没有urllib2,统一为了内置的urllib库;

    API:https://docs.python.org/3/library/urllib.html

    #该库提供了相关函数和类,基于身份认证、摘要身份验证、重定向、cookie的操作,实现完成(HTTP/1.1协议)的URL访问;

    该库主要包含以下四个模块:

    request,用于模拟浏览器发送请求;

    error,异常处理模块;

    parse,主要提供了对URL处理的方法,例如:拆分、转码、解析合并等;

    robotparser,用于识别网站的robots.txt文件,判断哪些网站可以爬取、哪些不可以,一般不使用;

    1、request模块:

    (1)方法:urlopen

      def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
    *, cafile=None, capath=None, cadefault=False, context=None):

      urlopen用于打开一个url,返回结果为HTTPResponse类型对象;

    参数:

      data可选参数,该字段可以是字节流编码格式,即bytes类型,则需要通过bytes()方法转化; 如果该参数不为空,表示该请求方式不再是GET请求方式,则是PPOST方式提交请求;

    timeout用于设置超时时间,单位秒,如果请求后超过该时间依然没有响应,则抛出异常;如果该参数未设置,那么会使用默认时间;他的支持仅是HTTP、HTTPS、FTP请求;

    其他参数:

    context,则必须是ssl.SSLContext类型,用于指定SSL设置;cafile和capath分别指定CA证书和它的路径,在HTTPS连接是会使用;

    cadefault参数忽略;

    例如:通过访问http://httpbin.org测试http请求(该站点可以测试http请求)

     1 #urllib(发送请求)
     2 #注意:python3以后将urlib2和urllib整合为了urllib,其中urllib的request不能直接用,需要urllib.request引入
     3 import urllib
     4 import urllib.parse
     5 import urllib.request
     6 
     7 data=bytes(urllib.parse.urlencode({'word':'hello'}),encoding='utf-8')
     8 response=urllib.request.urlopen('http://httpbin.org/post',data=data,timeout=1)#该地址可提供HTTP请求测试
     9 print(response.read().decode('utf-8'))
    10 print(type(response))#返回一个http.client.HTTPResponse对象
    11 print(response.status)#状态码
    12 print(response.getheaders())#相应头头信息
    13 print(response.getheader('Server'))#获取头信息中的Server服务名

    以上urlopen方法设置超时时间为1秒,如果超时则抛出urllib.error.URLError: <urlopen error timed out>异常;

    (2)类:Request

    class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)

    urlopen方法可以实现最基本的请求发起,但是简单的几个参数无法满足一个完整的请求;如果加入Headers等信息,则需要使用Request类来构建;

    使用该类,依然使用urlopen方法来发起请求,但是urlopen方法不再是一个字符串url,而是Request类型的字段;

    如下:

    1 #Request来构建请求
    2 
    3 import urllib
    4 import urllib.parse
    5 import urllib.request
    6 request=urllib.request.Request('http://python.org')
    7 response=urllib.request.urlopen(request)
    8 print(response.read().decode('utf-8'))

    参数:

    url必选,其他可选参数

    data,如果传入该参数,必须是bytes(字节流)类型,如果他是字典,则可以通过urllib.parse 中urlencode()进行编码

    headers参数是一个字典,他是请求头,在构建请求时可通过headers参数直接构建或者使用add_header()方法单独添加;

    添加请求头信息最常用方法是通过修改User-Agent伪装浏览器,默认User-Agent是Python-urllib;

    例如如果我们模拟发送请求时是使用的火狐浏览器,则可以设置

    User-Agent

    Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/64.0

    例如:

     1 #Request来构建请求
     2 
     3 import urllib
     4 import urllib.parse
     5 import urllib.request
     6 
     7 headers={"User-Agent":'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0',
     8                     #注意:"Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/64.0",这里我复制了火狐debug下url的请求信息,
     9                     # W... 没有显示全,因此粘贴过来少内容,报错:UnicodeEncodeError: 'latin-1' codec can't encode character 'u2026' in position。。。
    10           "Host":'httpbin.org'
    11          }
    12 data=bytes(urllib.parse.urlencode({'word':'Help'}),encoding='utf-8')
    13 request=urllib.request.Request('http://httpbin.org/post',headers=headers,data=data )
    14 #也可以通过add_header添加请求头信息
    15 request.add_header("Content-Type","application/x-www-form-urlencoded")
    16 
    17 response=urllib.request.urlopen(request)
    18 print(response.read().decode('utf-8'))
    19 
    20 
    21  

     (3)类:BaseHandler

     用于一些更高级操作,例如Cookies、代理操作等;

    子类:  HTTPDefaultErrorHandler 处理HTTP相应错误,抛出HTTPError异常

         HTTPREdirectHandler 处理重定向

           HTTPCookieProcessor处理Cookie

                     ProxyHandler设置代理,默认代理为空

          HTTPPasswordMgr 用于管理密码,他维护了用户名和密码的表

                    HTTPBasicAuthHandler用于管理可认证,如果一个连接打开时需要认证,则他可以解决认证问题;

    OpenerDirector,简称Opener,之前的urlopen实际就是urllib提供的一个简单的Opener;

    下面则通过Handler来构建Opener:

    例如:安装tomcat后访问tomcat首页面,http://localhost:8080/manager/html此时需要验证,

    此时可以进行下面代码来验证,通过显示源码:

    #Handler来构建Opener(做个登录验证)
    
    import urllib
    import urllib.parse
    import urllib.request
    from urllib.request import HTTPBasicAuthHandler,HTTPPasswordMgrWithDefaultRealm,build_opener
    from urllib.error import  URLError
    username="admin"
    pwd="admin"
    url="http://localhost:8080/manager/html"
    p=HTTPPasswordMgrWithDefaultRealm()
    p.add_password(None,url,username,pwd)
    authHandler=HTTPBasicAuthHandler(p)
    opener=build_opener(authHandler)
    result=opener.open(url)
    html=result.read().decode('utf-8')
    print(html)
     

    如果设置代理,则如下(未验证下面代码):

    proxyhandler=ProxyHandler({

    'http':'http://127.0.0.1:999',

    'https':'https://127.0.0.1:888'

    })

    opener=build_opener(proxyhandler)

    try:

       response=opener.open('https://www.baidu.com')

      print(response.read().decode('utf-8'))

    except URLError as e:

       print(e.reason)

     (4)获取请求后的Cookies

    可以通过声明一个CookieJar对象,利用HTTPCookieProcessor构建一个Handler,然后通过build_opener()方法创建opener,执行open方法即可;

    保存Cookies文件,则可以通过MozillaCookieJar或者LWPCookieJar 对象实现;

    例如:

     1 #获取网站的Cookies
     2 
     3 import urllib
     4 import urllib.parse
     5 import urllib.request
     6 from urllib.request import HTTPBasicAuthHandler,HTTPPasswordMgrWithDefaultRealm,build_opener
     7 from urllib.error import  URLError
     8 import http.cookiejar
     9 cookie=http.cookiejar.CookieJar()
    10 handler=urllib.request.HTTPCookieProcessor(cookie)
    11 opener=urllib.request.build_opener(handler)
    12 response=opener.open("http://www.baidu.com")
    13 for item in cookie:
    14      print(item.name+":"+item.value)
    15 
    16 #输出文本格式,则使用MozillaCookieJar
    17 filename='cookie.txt'
    18 cookie1=http.cookiejar.MozillaCookieJar(filename)
    19 handler1=urllib.request.HTTPCookieProcessor(cookie1)
    20 opener1=urllib.request.build_opener(handler1)
    21 response1=opener1.open("http://www.baidu.com")
    22 cookie1.save(ignore_discard=True,ignore_expires=True)
    23 
    24 #LWPCookieJar也可以保存Cookies,但是根式与上面不同;会保存为libwww-perl(LWP)格式的Cookies文件
    25 filename2='cookie2.txt'
    26 cookie2=http.cookiejar.LWPCookieJar(filename2)
    27 handler2=urllib.request.HTTPCookieProcessor(cookie2)
    28 opener2=urllib.request.build_opener(handler2)
    29 response2=opener2.open("http://www.baidu.com")
    30 cookie2.save(ignore_discard=True,ignore_expires=True)
    31

    如何利用取保存了cookies的文件数据?

    如下:

     1 #获取网站的Cookies
     2 
     3 import urllib
     4 import urllib.parse
     5 import urllib.request
     6 from urllib.request import HTTPBasicAuthHandler,HTTPPasswordMgrWithDefaultRealm,build_opener
     7 from urllib.error import  URLError
     8 import http.cookiejar
     9 cookie=http.cookiejar.CookieJar()
    10 handler=urllib.request.HTTPCookieProcessor(cookie)
    11 opener=urllib.request.build_opener(handler)
    12 response=opener.open("http://www.baidu.com")
    13 for item in cookie:
    14      print(item.name+":"+item.value)
    15 
    16 #输出文本格式,则使用MozillaCookieJar
    17 filename='cookie.txt'
    18 cookie1=http.cookiejar.MozillaCookieJar(filename)
    19 handler1=urllib.request.HTTPCookieProcessor(cookie1)
    20 opener1=urllib.request.build_opener(handler1)
    21 response1=opener1.open("http://www.baidu.com")
    22 cookie1.save(ignore_discard=True,ignore_expires=True)
    23 
    24 #LWPCookieJar也可以保存Cookies,但是根式与上面不同;会保存为libwww-perl(LWP)格式的Cookies文件
    25 filename2='cookie2.txt'
    26 cookie2=http.cookiejar.LWPCookieJar(filename2)
    27 handler2=urllib.request.HTTPCookieProcessor(cookie2)
    28 opener2=urllib.request.build_opener(handler2)
    29 response2=opener2.open("http://www.baidu.com")
    30 cookie2.save(ignore_discard=True,ignore_expires=True)
    31 
    32 #加载cookie.txt,访问百度来搜索数据
    33 cookie = http.cookiejar. LWPCookieJar()
    34 cookie.load('cookie2.txt',ignore_discard=True, ignore_expires=True)
    35 handler = urllib.request.HTTPCookieProcessor(cookie)
    36 opener = urllib .request.build_opener(handler)
    37 response= opener.open('http://www.baidu.com/baidu?word=Python')
    38 print (response. read(). decode ('utf-8'))

     2、关于异常处理

    urllib的error模块定义了又request模块产生的异常。

    URLError类:

    URLError类是来自于urllib库的error模块,继承自OSError类,是error异常类的基类,由request模块产生的异常都可以捕获处理到;

    它具有一个属性reason,返回错误的消息;

    例如:访问了一个网站不存在的页面;

     1 #关于异常URLError
     2 
     3 import urllib
     4 import urllib.parse
     5 import urllib.request
     6 from urllib.request import HTTPBasicAuthHandler,HTTPPasswordMgrWithDefaultRealm,build_opener
     7 from urllib.error import  URLError
     8 import http.cookiejar
     9 
    10 
    11 try:
    12        response=urllib.request.urlopen("https://i.cnblogs.com/a.html") 
    13 except URLError as e:
    14 print(e.reason)

    结果为Not Found;

    HTTPError类:

    他是URLError的子类,专门用于处理Http请求错误,例如认证请求失败

    code:返回HTTP状态码,例如:404,500等状态码

    reason,返回错误信息

    headers:返回请求头

    例如:

    1 try:
    2      response=urllib.request.urlopen("https://i.cnblogs.com/a.html")
    3 except  HTTPError as e:
    4      print(e.reason,e.code,e.headers)

    两者父子关系,我们也可以先捕子类型错误,再补货父类类型错误;

    例如:

    1 try:
    2      response=urllib.request.urlopen("https://i.cnblogs.com/a.html")
    3 except  HTTPError as e:
    4      print(e.reason,e.code,e.headers,sep='
    ')
    5 except URLError as e:
    6      print(e.reason)
    7 else:
    8      print("无异常")

    有时候异常信息是一个对象,例如:

    1 try:
    2      response = urllib.request.urlopen("https://www.baidu.com",timeout=0.01)
    3 except  HTTPError as e:
    4      print(type(e.reason))
    5 except URLError as e: #请求超时,此时被URLError异常捕获
    6      print(type(e.reason))#<class 'socket.timeout'>是一个异常对象
    7 else:
    8      print("无异常")

    再次修改上面

    的程序,通过isinstance来判断是那种对象,来给具体异常信息描述;

    #前面import略
    import socket
    try:
         response = urllib.request.urlopen("https://www.baidu.com",timeout=0.01)
    except  HTTPError as e:
         print(type(e.reason))
    except URLError as e: #请求超时,此时被URLError异常捕获
         print(type(e.reason))#<class 'socket.timeout'>是一个异常对象
         if isinstance(e.reason,socket.timeout):
              print("Time Out")
    else:
         print("无异常")

     3.链接解析:

    urllib中的parse模块提供了chuliURL的标准接口,例如,url的各部分抽取,合并以及连接转换等;支持一下协议的URL处理:

    file、ftp、gopher、hdl、http/https、imap、mailto、mms、news、nntp、prospero、rsync、rtsp、rtspu、sftp、sip、snews、svn、svn+ssh、

    telnet和wais;

    常用方法如下:

    ①urlparse()提供了url的识别和分段;返回元组对象;

    例如:(allow_fragments=False 可以忽略fragment))

     1 #关于异常URLparse
     2 
     3 import urllib
     4 from urllib.parse import  urlparse
     5 result=urlparse("http://www.baidu.com/index.html;user?id=5#comment")
     6 print(type(result),result)
     7 #<class 'urllib.parse.ParseResult'> ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')
     8 # ://前是scheme,代表协议; 第一个/前面是netloc,即域名;后面是path,即访问路径;分号后,是params,代表参数;?号后表示查询条件;#号后是锚点用户直接定位到当前页某个位置
     9 #即根据scheme://netloc/path;params?query#fragment 格式进行的拆分;
    10 
    11 #例如:url没有scheme,可以通过参数设置;前提是url没有写scheme,否则scheme参数设置失效
    12 result=urlparse("www.baidu.com/index.html;user?id=5#comment",scheme="http") 13 print(type(result),result)

    ②unurlparse()及将一个列表中的元素,组成为一个完整url

    前提是该方法参数必须是6个参数,否则报错;

    例如:data=['http','www.baidu.com','/index.html', 'user', 'id=5', 'comment']

    unurlparse(data) 该结果则为http://www.baidu.com/index.html;user?id=5#comment

    ③urlsplit()将一个一个url拆分;unsplit()与之相反;

    例如:

    1 r=urlsplit("http://www.baidu.com/index.html;user?id=5#comment")#不包含params,注意
    2 print( (r))
    3 print( r[0],r[1],r[2],r[3],r[4])

    ④urljoin() 连接多个url,将他们合并;

    例如:

    rom urllib.parse import urljoin
    print(urljoin(' http: I lwww. baidu. com', 'FAQ. html ’))
    print(urljoin('http://www.baidu.com ', ’ https://cuiqingcai . com/FAQ . html ’))

    结果为:

    http://www.baidu.com/FAQ.html
    https://cuiqingcai.com/FAQ.html

    ⑤urlencode()

    例如:

    from urllib .parse import urlencode
    params = {
    ’ name' 'JONES' ,
    age : 30

    }

    url='http://www.baidu.com?'+urlencode(params)

    print(url)

    结果为:

    http://www.baidu.com?name=JONES&age=30

    ⑥parse_qs()

    urlencode相当于序列化操作,而parse_qs()则相当于反序列化操作;

    例如:

    from urllib.parse import parse qs
    query= 'name=germey&age=22'
    print(parse_qs(query))

    结果:

    {’ name': [’ germey ’],’ age ' : [ ’ 22 ' ]}

    ⑦、quote()

    该方法讲内容转为URL编码的格式。

    例如:

    keyword=’张三’
    url =’ https://www.baidu.com/s?wd =’+ quote(keyword)
    print(url)

    结果为:

    https://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8

    ⑧、unquote() 与上面quote()方法操作相反效果;

     4、robotparser

    即Python中用于解析robots.txt文件的模块, Robots是一种协议,被叫做爬虫协议、机器人协议,他全名叫做网络爬虫排除标准(Robots Exclusion Protocol)

    用于告诉爬虫和搜索引擎哪些页面可以抓取,那些不可以;一般网站项目根目录中会有一个robots.txt文件,来设置那些不允许被抓取;

    例如:该文件中如果

    User-agent: *
    Disallow: I
    Allow: /public/

    则表示对所有爬虫只允许抓取public目录;

    爬虫一般会有名字,例如百度(搜索引擎会有蜘蛛来爬取网页)的蜘蛛名字为:BaiduSpider,其他网站不说了这里;

    例如:访问xx网站

     1 import urllib.robotparser
     2 
     3 rp = urllib.robotparser.RobotFileParser()
     4 rp.set_url('http://example.com/robots.txt')
     5 rp.read()
     6 url = 'http://example.com'
     7 user_agent = 'BadCrawler'
     8 f=rp.can_fetch(user_agent, url)#是否允许指定的用户代理访问网页
     9 print(f)
    10 user_agent = 'GoodCrawler'
    11 n=rp.can_fetch(user_agent, url)
    12 print(n)

  • 相关阅读:
    算法导论第十八章 B树
    腾讯2016春招之算法编程解析
    LeetCode:5_Longest Palindromic Substring | 最长的回文子串 | Medium
    搜狗2016校园招聘之算法编程解析
    linux sed在某些字符串的下一行插入内容?sed在下一行插入?
    linux shell搜索某个字符串,然后在后面加上字符串?字符串后面插入字符串?sed字符串后面插入字符串?
    linux环境中,如何使用tar来创建压缩包?解压缩?
    linux环境中,ssh登录报错,Permission denied, please try again.
    linux环境中安装NRPE插件执行远程"本地资源"检查?NRPE安装?
    linux环境安装nagiosgraph将nagios的性能数据绘制成动态图表?
  • 原文地址:https://www.cnblogs.com/ygzhaof/p/10148344.html
Copyright © 2011-2022 走看看