python爬虫之urllib库(一)

  urllib库

  urllib库是python提供的一种用于操作URL的模块,python2中是urllib和urllib2两个库文件,python3中整合在了urllib一个库中。即在Python中导入和调用方法也发生了改变。

python2和python3中urllib库变化对比
python2 python3
import urllib2 import urllib.request,urllib.request
import urllib import urllib.reqest,urllib.error,urllib.parse
import parse import urllib.parse
urllib2.urlopen urllib.request.urlopen
urllib.urlencode urllib.parse.urlencode
urllib.quote urllib.request.quote
cookielib.CookieJar http.CookieJar
urllib2.Request urllib.request.Request

  使用urllib库快速爬取网页

  使用urllib库需要导入urllib库中对应的模块。

  1.   import urllib.request

  导入对应模块以后,使用模块中的urlopen()方法打开并爬取网页。例如,爬取百度首页(http://www.baidu.com),并保存在变量file中。

  1.   file = urllib.request.urlopen(‘http://www.baidu.com’)

  使用print(file)查看一下变量file中保存的内容,查看结果为:<http.client.HTTPResponse object at 0x0000000002DCBB38>。由此看出,urlopen()方法爬取网页返回的结果是一个HTTP响应对象,读取对象中的内容需要其他方式。

  读取内容的三种方式及其用法:

  1. file.read()读取文件的全部内容,read()方法读取的内容赋值给一个字符串变量。
  2. file.readlines()读取文件的全部内容,readlines()方法读取的内容赋值给一个列表变量。
  3. file.readline()读取文件的一行内容。
  1. data = file.read() # 所有内容赋值给字符串
  2. print(data)
  3. data_lines = file.readlines() # 所有内容赋值给列表
  4. print(data_lines)
  5. data_line = file.readline() # 单行内容
  6. print(data_line)
  7. data_line_next = file.readline()
  8. print(data_line_next) # 读取下一行

  成功爬取了一个网页以后,将网页保存在本地需要使用文件读写操作。文件读写的具有两种写法:

  法一:

  1. fhandle = open('D:/Spider/test/baidu.html', 'wb')
  2. fhandle.write(data)
  3. fhandle.close()

  法二:

  1.   with open('D:/Spider/test/baidu.html', 'wb') as fhandle:
  2.   fhandle.write(data)

  两种写法都是先使用open()方法按照文件目录D:/Spider/test/ 找到并打开名为baidu.html的文件,文件操作模式为'wb',表示bytes类型数据写模式,然后使用write()方法写入。区别在于with方法在数据写入以后会自动关闭文件,而法一需要调用close()方法关闭文件。

  注意一个问题:urlopen()返回的HTTP响应对象通过head()读取以后,可以看到b‘  ’形式的字符串,此类型数据为bytes类型,对应文件写入的中'wb',‘rb’等。我们知道python中,bytes类型数据是适合用于数据的传输和存储,而如果bytes类型数据需要处理,则需要转化为str类型数据。

  str类型与bytes类型之间的数据转换方式:

  1. str类型数据转化为bytes类型数据:编码,str.encode('utf-8'),其中utf-8为统一码,是一种编码格式。
  2. bytes类型数据转化为str类型数据:解码,bytes.decode('utf-8')。
  1. import urllib.request
  2.  
  3. file = urllib.request.urlopen('http://www.baidu.com')
  4. data = file.read().decode() # decode()转bytes为str
  5.  
  6. with open('D:/Spider/test/baidu.html', 'w') as fhandle: # 以str类型写入文件
  7. fhandle.write(data)

  按照文件目录找到baidu.html文件,使用浏览器打开,可以看到本地版百度首页。只是图片暂时没有爬取过来。

  此外,可以使用getcode()方法查看爬取网页时的状态码,geturl()方法获取当时爬取的url地址。

  1. import urllib.request
  2.  
  3. file = urllib.request.urlopen('http://www.baidu.com')
  4. code = file.getcode()
  5. url = file.geturl()
  6. print(code)
  7. print(url)

  除了上面使用的方法,还可以使用urllib.request中urlretrieve()方法直接将对应信息写入本地文件,格式:urllib.request.urlretrieve(url, filename = '本地文件地址')。

  1. import urllib.request
  2.  
  3. url = 'http://www.baidu.com'
  4. filename = urllib.request.urlretrieve(url, filename='D:/Spider/test/baidu-2.html')

  按照文件目录找到baidu-2.html文件,使用浏览器打开,可以看到本地版百度首页。此外,使用print(filename)查看,得出('D:/Spider/test/baidu-2.html', <http.client.HTTPMessage object at 0x0000000002DEC2E8>),filename是以元组形式存储了本地文件地址和HTTP响应消息对象。

  使用urllib.request.retrieve()方法爬取网页本地化保存会产生一些缓存,可以使用urlcleanup()方法清除缓存。

  1.   urllib.request.urlcleanup()

  URL编码:一般来说,URL标准只允许一部分ASCII字符在url中使用,像汉字、“:”、“&”等字符是不符合URL标准的,需要进行URL编码。根据传参形式不同,URL编码又分为两种方式。

  方式一:使用urllib.request.quote()对单一参数进行编码。

  1. url = 'http://www.baidu.com/s?wd='
  2. search = '编程' # 单一参数
  3. search_url = url + urllib.request.quote(search) # 参数编码,合并url
  4. print(search_url)

  方式二:使用urllib.parse.urlencode()对多个参数以字典形式传入进行编码。

  1. import urllib.parse
  2.  
  3. url = 'http://www.baidu.com/s?'
  4. params = {
  5. 'wd': '中文',
  6. 'key': '张',
  7. 'value': '三'
  8. }
  9.  
  10. str_params = urllib.parse.urlencode(params) # 字典传参拼接方式,urlencode()和quote()相似,urlencode对多个参数转义
  11. print(str_params) # wd=%E4%B8%AD%E6%96%87&key=%25E5%25BC%25A0&value=%E4%B8%89
  12. search_url = url + str_params
  13. print(search_url)

  使用headers属性模拟浏览器

  有时,使用爬虫爬取一些网页的时候,会返回403错误,即禁止访问的错误。是因为网页为了防止恶意采集信息的行为设置了一些反爬措施。对于这部分网页,我们可以尝试设置一些headers信息,模拟成浏览器去访问这些网页。由于urlopen()不支持一些HTTP的高级特性,要添加可以使用opener对象或者Request类来进行。

  三种添加headers信息的方式,参阅python爬虫之User-Agent用户信息

  方法一:使用build_opener()修改报头

  1. import urllib.request
  2.  
  3. url= "http://blog.csdn.net/weiwei_pig/article/details/51178226"
  4. headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0")
  5.  
  6. opener = urllib.request.build_opener()
  7. opener.addheaders = [headers]
  8. data=opener.open(url).read()

  通过build_opener()方法创建opener对象,而opener对象是由OpenerDirector类实例化来的。

  OpenerDirector类的实例属性self.addheaders默认初始值为[('User-agent', client_version)](列表元素为元组型嵌套),外部调用赋值修改opener.addheaders属性。

  后调用OpenerDirector类的实例方法open()发送HTTP请求。

  方法二:使用Request类实例化静态添加报头

  1. import urllib.request
  2.  
  3. url= "http://www.baidu.com"
  4. headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0")
  5.  
  6. req=urllib.request.Request(url, headers= headers)
  7. data=urllib.request.urlopen(req).read()

  方法三:使用Request类的实例方法add_headers()动态添加报头(注意源码中add_headers()方法的首字母大写的key才可以取value)

  1. import urllib.request
  2.  
  3. url= "http://www.baidu.com"
  4.  
  5. req=urllib.request.Request(url)
  6. req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0')
  7. data=urllib.request.urlopen(req).read()

  方法二和方法三都是对Request类的操作,方法二是通过对类的初始化添加headers,方法三是调用类中的实例方法add_header()添加headers,Request类源码:

  1. class Request:
  2.  
  3. def __init__(self, url, data=None, headers={},
  4. origin_req_host=None, unverifiable=False,
  5. method=None):
  6. self.full_url = url
  7. self.headers = {}
  8. self.unredirected_hdrs = {}
  9. self._data = None
  10. self.data = data
  11. self._tunnel_host = None
  12. for key, value in headers.items():
  13. self.add_header(key, value)
  14. if origin_req_host is None:
  15. origin_req_host = request_host(self)
  16. self.origin_req_host = origin_req_host
  17. self.unverifiable = unverifiable
  18. if method:
  19. self.method = method
  20.  
  21. @property
  22. def full_url(self):
  23. if self.fragment:
  24. return '{}#{}'.format(self._full_url, self.fragment)
  25. return self._full_url
  26.  
  27. @full_url.setter
  28. def full_url(self, url):
  29. # unwrap('<URL:type://host/path>') --> 'type://host/path'
  30. self._full_url = unwrap(url)
  31. self._full_url, self.fragment = splittag(self._full_url)
  32. self._parse()
  33.  
  34. @full_url.deleter
  35. def full_url(self):
  36. self._full_url = None
  37. self.fragment = None
  38. self.selector = ''
  39.  
  40. @property
  41. def data(self):
  42. return self._data
  43.  
  44. @data.setter
  45. def data(self, data):
  46. if data != self._data:
  47. self._data = data
  48. # issue 16464
  49. # if we change data we need to remove content-length header
  50. # (cause it's most probably calculated for previous value)
  51. if self.has_header("Content-length"):
  52. self.remove_header("Content-length")
  53.  
  54. @data.deleter
  55. def data(self):
  56. self.data = None
  57.  
  58. def _parse(self):
  59. self.type, rest = splittype(self._full_url)
  60. if self.type is None:
  61. raise ValueError("unknown url type: %r" % self.full_url)
  62. self.host, self.selector = splithost(rest)
  63. if self.host:
  64. self.host = unquote(self.host)
  65.  
  66. def get_method(self):
  67. """Return a string indicating the HTTP request method."""
  68. default_method = "POST" if self.data is not None else "GET"
  69. return getattr(self, 'method', default_method)
  70.  
  71. def get_full_url(self):
  72. return self.full_url
  73.  
  74. def set_proxy(self, host, type):
  75. if self.type == 'https' and not self._tunnel_host:
  76. self._tunnel_host = self.host
  77. else:
  78. self.type= type
  79. self.selector = self.full_url
  80. self.host = host
  81.  
  82. def has_proxy(self):
  83. return self.selector == self.full_url
  84.  
  85. def add_header(self, key, val):
  86. # useful for something like authentication
  87. self.headers[key.capitalize()] = val
  88.  
  89. def add_unredirected_header(self, key, val):
  90. # will not be added to a redirected request
  91. self.unredirected_hdrs[key.capitalize()] = val
  92.  
  93. def has_header(self, header_name):
  94. return (header_name in self.headers or
  95. header_name in self.unredirected_hdrs)
  96.  
  97. def get_header(self, header_name, default=None):
  98. return self.headers.get(
  99. header_name,
  100. self.unredirected_hdrs.get(header_name, default))
  101.  
  102. def remove_header(self, header_name):
  103. self.headers.pop(header_name, None)
  104. self.unredirected_hdrs.pop(header_name, None)
  105.  
  106. def header_items(self):
  107. hdrs = self.unredirected_hdrs.copy()
  108. hdrs.update(self.headers)
  109. return list(hdrs.items())

  考虑:实例属性self.headers初始值为空字典{},能否像方法一,在外部调用时赋值修改实例属性。

  1. import urllib.request
  2.  
  3. url = "http://www.baidu.com"
  4. headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0"}
  5.  
  6. req = urllib.request.Request(url)
  7. req.headers = headers
  8. data = urllib.request.urlopen(req).read()
  9.  
  10. with open('t.html', 'wb') as fhandle:
  11. fhandle.write(data)

  测试验证方法,找到t.html文件使用浏览器打开,按F12切换到DevTools-Network选项,刷新页面,出现

  点击黑色箭头所指列表项的任意一下,右侧出现

  下拉找到Request Headers,展开找到User-Agent项,对照上述代码User-Agent信息验证可以使用外部调用实例属性修改。

  上述过程反过来,则为手动抓包,获取User-Agent信息了。

  

  

python爬虫之urllib库(一)的更多相关文章

  1. python爬虫之urllib库(三)

    python爬虫之urllib库(三) urllib库 访问网页都是通过HTTP协议进行的,而HTTP协议是一种无状态的协议,即记不住来者何人.举个栗子,天猫上买东西,需要先登录天猫账号进入主页,再去 ...

  2. python爬虫之urllib库(二)

    python爬虫之urllib库(二) urllib库 超时设置 网页长时间无法响应的,系统会判断网页超时,无法打开网页.对于爬虫而言,我们作为网页的访问者,不能一直等着服务器给我们返回错误信息,耗费 ...

  3. python爬虫之urllib库介绍

    一.urllib库 urllib是Python自带的一个用于爬虫的库,其主要作用就是可以通过代码模拟浏览器发送请求.其常被用到的子模块在Python3中的为urllib.request和urllib. ...

  4. python 爬虫之 urllib库

    文章更新于:2020-03-02 注:代码来自老师授课用样例. 一.初识 urllib 库 在 python2.x 版本,urllib 与urllib2 是两个库,在 python3.x 版本,二者合 ...

  5. Python 爬虫之urllib库的使用

    urllib库 urllib库是Python中一个最基本的网络请求库.可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据. urlopen函数: 在Python3的urlli ...

  6. python爬虫入门urllib库的使用

    urllib库的使用,非常简单. import urllib2 response = urllib2.urlopen("http://www.baidu.com") print r ...

  7. python爬虫之urllib库

    请求库 urllib urllib主要分为几个部分 urllib.request 发送请求urllib.error 处理请求过程中出现的异常urllib.parse 处理urlurllib.robot ...

  8. Python爬虫系列-Urllib库详解

    Urllib库详解 Python内置的Http请求库: * urllib.request 请求模块 * urllib.error 异常处理模块 * urllib.parse url解析模块 * url ...

  9. python爬虫03 Urllib库

    Urllib   这可是 python 内置的库 在 Python 这个内置的 Urllib 库中 有这么 4 个模块 request request模块是我们用的比较多的 就是用它来发起请求 所以我 ...

随机推荐

  1. thinkpad t480s重装win10后小红点失灵 无法启用

    问题描述: thinkpad t480s重装win10纯净版系统后,小红点失效,控制面板中Track Point设置页面被禁用. 解决方法: 可打开下述网址,下载并安装TrackPoint Firmw ...

  2. js实现二级菜单显示和收缩

    window.onload=function(){ var aLi=document.getElementsByTagName('li'); for(var i=0; i<aLi.length; ...

  3. 执行“hdfs dfs -ls”时报ConnectException

    原因可能是指定的端口号不对,该端口号由hdfs-site.xml中的属性"dfs.namenode.rpc-address"指定,即为NameNode的RPC服务端口号. 文件上传 ...

  4. solr&lucene3.6.0源码解析(一)

      本文作为系列的第一篇,主要描述的是solr3.6.0开发环境的搭建   首先我们需要从官方网站下载solr的相关文件,下载地址为http://archive.apache.org/dist/luc ...

  5. Java多线程设计模式(二)

        目录(?)[-] Guarded Suspension Pattern Balking Pattern Producer-Consumer Pattern   Guarded Suspensi ...

  6. python3操作Excel openpyxl模块的使用

    python 与excel 安装模块 本例子中使用的模块为: openpyxl 版本为2.4.8 安装方法请参看以前发表的文章(Python 的pip模块安装方法) Python处理Excel表格 使 ...

  7. [转发]Oauth 1.0 1.0a 和 2.0 的之间的区别有哪些?

    原文地址:http://www.zhihu.com/question/19851243

  8. Java Integer为代表的包装类

    Java种的Integer是int的包装类型 1. Integer 是int的包装类型,数据类型是类,初值为null 2. 初始化时 int i = 1; Integer i = new Intege ...

  9. MFC学习(三):项目学习

    1. 概述 MFC程序由CWinApp.MainFrm(含Menu,可用CSplitterWndEx分割).众多Dialog等组成. MFC既可以使用纯Dialog的形式,也可以使用Document+ ...

  10. System.Data.OracleClient.dll方式操作oracle数据库

    System.Data.OracleClient.dll方式操作oracle数据库 一.查询语句: using (OracleConnection conn = new OracleConnectio ...