深入解析Python中的urllib2模块


Posted in Python onNovember 13, 2015

Python 标准库中有很多实用的工具类,但是在具体使用时,标准库文档上对使用细节描述的并不清楚,比如 urllib2 这个 HTTP 客户端库。这里总结了一些 urllib2 的使用细节。

  • Proxy 的设置
  • Timeout 设置
  • 在 HTTP Request 中加入特定的 Header
  • Redirect
  • Cookie
  • 使用 HTTP 的 PUT 和 DELETE 方法
  • 得到 HTTP 的返回码
  • Debug Log

Proxy 的设置

urllib2 默认会使用环境变量 http_proxy 来设置 HTTP Proxy。如果想在程序中明确控制 Proxy 而不受环境变量的影响,可以使用下面的方式

import urllib2
enable_proxy = True
proxy_handler = urllib2.ProxyHandler({"http" : 'http://some-proxy.com:8080'})
null_proxy_handler = urllib2.ProxyHandler({})

if enable_proxy:
opener = urllib2.build_opener(proxy_handler)
else:
opener = urllib2.build_opener(null_proxy_handler)

urllib2.install_opener(opener)

这里要注意的一个细节,使用 urllib2.install_opener() 会设置 urllib2 的全局 opener 。这样后面的使用会很方便,但不能做更细粒度的控制,比如想在程序中使用两个不同的 Proxy 设置等。比较好的做法是不使用 install_opener 去更改全局的设置,而只是直接调用 opener 的 open 方法代替全局的 urlopen 方法。

Timeout 设置

在老版 Python 中,urllib2 的 API 并没有暴露 Timeout 的设置,要设置 Timeout 值,只能更改 Socket 的全局 Timeout 值。

import urllib2


import socket
socket.setdefaulttimeout(10) # 10 秒钟后超时
urllib2.socket.setdefaulttimeout(10) # 另一种方式

在 Python 2.6 以后,超时可以通过 urllib2.urlopen() 的 timeout 参数直接设置。

import urllib2
response = urllib2.urlopen('http://www.google.com', timeout=10)

在 HTTP Request 中加入特定的 Header

要加入 header,需要使用 Request 对象:

import urllib2
request = urllib2.Request(uri)
request.add_header('User-Agent', 'fake-client')
response = urllib2.urlopen(request)

对有些 header 要特别留意,服务器会针对这些 header 做检查

User-Agent : 有些服务器或 Proxy 会通过该值来判断是否是浏览器发出的请求

Content-Type : 在使用 REST 接口时,服务器会检查该值,用来确定 HTTP Body 中的内容该怎样解析。常见的取值有:

  • application/xml : 在 XML RPC,如 RESTful/SOAP 调用时使用
  • application/json : 在 JSON RPC 调用时使用
  • application/x-www-form-urlencoded : 浏览器提交 Web 表单时使用

在使用服务器提供的 RESTful 或 SOAP 服务时, Content-Type 设置错误会导致服务器拒绝服务

Redirect

urllib2 默认情况下会针对 HTTP 3XX 返回码自动进行 redirect 动作,无需人工配置。要检测是否发生了 redirect 动作,只要检查一下 Response 的 URL 和 Request 的 URL 是否一致就可以了。

import urllib2
response = urllib2.urlopen('http://www.google.cn')
redirected = response.geturl() == 'http://www.google.cn'

如果不想自动 redirect,除了使用更低层次的 httplib 库之外,还可以自定义 HTTPRedirectHandler 类。

import urllib2

class RedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_301(self, req, fp, code, msg, headers):
pass
def http_error_302(self, req, fp, code, msg, headers):
pass

opener = urllib2.build_opener(RedirectHandler)
opener.open('http://www.google.cn')

Cookie

urllib2 对 Cookie 的处理也是自动的。如果需要得到某个 Cookie 项的值,可以这么做:

import urllib2
import cookielib

cookie = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
response = opener.open('http://www.google.com')
for item in cookie:
if item.name == 'some_cookie_item_name':
print item.value

使用 HTTP 的 PUT 和 DELETE 方法

urllib2 只支持 HTTP 的 GET 和 POST 方法,如果要使用 HTTP PUT 和 DELETE ,只能使用比较低层的 httplib 库。虽然如此,我们还是能通过下面的方式,使 urllib2 能够发出 PUT 或 DELETE 的请求:

import urllib2

request = urllib2.Request(uri, data=data)
request.get_method = lambda: 'PUT' # or 'DELETE'
response = urllib2.urlopen(request)

得到 HTTP 的返回码

对于 200 OK 来说,只要使用 urlopen 返回的 response 对象的 getcode() 方法就可以得到 HTTP 的返回码。但对其它返回码来说,urlopen 会抛出异常。这时候,就要检查异常对象的 code 属性了:

import urllib2
try:
response = urllib2.urlopen('http://restrict.web.com')
except urllib2.HTTPError, e:
print e.code
Debug Log

使用 urllib2 时,可以通过下面的方法把 debug Log 打开,这样收发包的内容就会在屏幕上打印出来,方便调试,有时可以省去抓包的工作

import urllib2

httpHandler = urllib2.HTTPHandler(debuglevel=1)
httpsHandler = urllib2.HTTPSHandler(debuglevel=1)
opener = urllib2.build_opener(httpHandler, httpsHandler)

urllib2.install_opener(opener)
response = urllib2.urlopen('http://www.google.com')

PS: 借助urllib2抓取网站生成RSS
看了看OsChina的博客页面,发现可以使用python来抓取.记得前段时间看到有人使用python的RSS模块PyRSS2Gen生成了RSS.于是忍不住手痒自己试着实现了下,幸好还是成功了,下面代码共享给大家.
首先需要安装PyRSS2Gen模块和BeautifulSoup模块,pip安装下就好了,我就不再赘述了.
下面贴出代码

# -*- coding: utf-8 -*-


from bs4 import BeautifulSoup
import urllib2

import datetime
import time
import PyRSS2Gen
from email.Utils import formatdate
import re
import sys
import os
reload(sys)
sys.setdefaultencoding('utf-8')




class RssSpider():
  def __init__(self):
    self.myrss = PyRSS2Gen.RSS2(title='OSChina',
                  link='http://my.oschina.net',
                  description=str(datetime.date.today()),
                  pubDate=datetime.datetime.now(),
                  lastBuildDate = datetime.datetime.now(),
                  items=[]
                  )
    self.xmlpath=r'/var/www/myrss/oschina.xml'

    self.baseurl="http://www.oschina.net/blog"
    #if os.path.isfile(self.xmlpath):
      #os.remove(self.xmlpath)
  def useragent(self,url):
    i_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) \
  AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36", \
  "Referer": 'http://baidu.com/'}
    req = urllib2.Request(url, headers=i_headers)
    html = urllib2.urlopen(req).read()
    return html
  def enterpage(self,url):
    pattern = re.compile(r'\d{4}\S\d{2}\S\d{2}\s\d{2}\S\d{2}')
    rsp=self.useragent(url)
    soup=BeautifulSoup(rsp)
    timespan=soup.find('div',{'class':'BlogStat'})
    timespan=str(timespan).strip().replace('\n','').decode('utf-8')
    match=re.search(r'\d{4}\S\d{2}\S\d{2}\s\d{2}\S\d{2}',timespan)
    timestr=str(datetime.date.today())
    if match:
      timestr=match.group()
      #print timestr
    ititle=soup.title.string
    div=soup.find('div',{'class':'BlogContent'})
    rss=PyRSS2Gen.RSSItem(
               title=ititle,
               link=url,
               description = str(div),
               pubDate = timestr
               )

    return rss
  def getcontent(self):
    rsp=self.useragent(self.baseurl)
    soup=BeautifulSoup(rsp)
    ul=soup.find('div',{'id':'RecentBlogs'})
    for li in ul.findAll('li'):
      div=li.find('div')
      if div is not None:
        alink=div.find('a')
        if alink is not None:
          link=alink.get('href')
          print link
          html=self.enterpage(link)
          self.myrss.items.append(html)
  def SaveRssFile(self,filename):
    finallxml=self.myrss.to_xml(encoding='utf-8')
    file=open(self.xmlpath,'w')
    file.writelines(finallxml)
    file.close()



if __name__=='__main__':
  rssSpider=RssSpider()
  rssSpider.getcontent()
  rssSpider.SaveRssFile('oschina.xml')

可以看到,主要是使用BeautifulSoup来抓取站点然后使用PyRSS2Gen来生成RSS并保存为xml格式文件.
顺便共享下我生成的RSS地址

http://104.224.129.109/myrss/oschina.xml

大家如果不想折腾的话直接使用feedly订阅就行了.
脚本我会每10分钟执行一次的.

Python 相关文章推荐
Python获取电脑硬件信息及状态的实现方法
Aug 29 Python
centos 下面安装python2.7 +pip +mysqld
Nov 18 Python
Python获取服务器信息的最简单实现方法
Mar 05 Python
详解Python 解压缩文件
Apr 09 Python
python应用文件读取与登录注册功能
Sep 23 Python
DJANGO-URL反向解析REVERSE实例讲解
Oct 25 Python
Python获取二维数组的行列数的2种方法
Feb 11 Python
解决springboot yml配置 logging.level 报错问题
Feb 21 Python
linux 下selenium chrome使用详解
Apr 02 Python
keras 多任务多loss实例
Jun 22 Python
你需要学会的8个Python列表技巧
Jun 24 Python
python 下划线的多种应用场景总结
May 12 Python
Python下的常用下载安装工具pip的安装方法
Nov 13 #Python
Python的Flask框架的简介和安装方法
Nov 13 #Python
Python编程入门之Hello World的三种实现方式
Nov 13 #Python
python编程开发之textwrap文本样式处理技巧
Nov 13 #Python
python编程开发之日期操作实例分析
Nov 13 #Python
python编程开发之类型转换convert实例分析
Nov 13 #Python
python开发之文件操作用法实例
Nov 13 #Python
You might like
php使用gettimeofday函数返回当前时间并存放在关联数组里
2015/03/19 PHP
浅谈PHP中JSON数据操作
2015/07/01 PHP
TP5框架实现自定义分页样式的方法示例
2020/04/05 PHP
JQuery 操作Javascript对象和数组的工具函数小结
2010/01/22 Javascript
利用div+jquery自定义滚动条样式的2种方法
2013/07/18 Javascript
Jquery插件实现点击获取验证码后60秒内禁止重新获取
2015/03/13 Javascript
使用JavaScript为Kindeditor自定义按钮增加Audio标签
2016/03/18 Javascript
浅析JavaScript 箭头函数 generator Date JSON
2016/05/23 Javascript
javascript添加前置0(补零)的几种方法
2017/01/05 Javascript
从零开始学习Node.js系列教程之设置HTTP头的方法示例
2017/04/13 Javascript
将angular.js项目整合到.net mvc中的方法详解
2017/06/29 Javascript
详细分析JS函数去抖和节流
2017/12/05 Javascript
vue.js分页中单击页码更换页面内容的方法(配合spring springmvc)
2018/02/10 Javascript
JS装饰器函数用法总结
2018/04/21 Javascript
vue-cli配置环境变量的方法
2018/07/09 Javascript
vue中动态设置meta标签和title标签的方法
2018/07/11 Javascript
webuploader实现上传图片到服务器功能
2018/08/16 Javascript
解决betterScroll在vue中存在图片时,出现拉不动的问题
2018/09/27 Javascript
vue使用codemirror的两种用法
2019/08/27 Javascript
Vue 通过公共字段,拼接两个对象数组的实例
2019/11/07 Javascript
vue项目中使用eslint+prettier规范与检查代码的方法
2020/01/16 Javascript
在vue中实现清除echarts上次保留的数据(亲测有效)
2020/09/09 Javascript
vue v-model的用法解析
2020/10/19 Javascript
Python 列表理解及使用方法
2017/10/27 Python
Python基础语言学习笔记总结(精华)
2017/11/14 Python
python处理DICOM并计算三维模型体积
2019/02/26 Python
Levi’s西班牙官方网站:李维斯,著名的牛仔裤品牌
2020/08/20 全球购物
怎样声明子类
2013/07/02 面试题
五一家具促销方案
2014/01/10 职场文书
社区志愿者活动总结
2014/06/26 职场文书
小学课外活动总结
2014/07/09 职场文书
小学优秀教师先进事迹材料
2014/12/16 职场文书
房产公证书样本
2015/01/23 职场文书
2015年社会治安综合治理工作总结
2015/04/10 职场文书
电影建国大业观后感
2015/06/01 职场文书
Smart 2 车辆代号 HC11 全新谍照曝光
2022/04/21 数码科技