之前看到geventhttpclient这个项目,https://github.com/gwik/geventhttpclient,官方文档说非常快,因为响应使用了C的解析,所以我一直想把这玩意用到项目中,

这两天一直在纠结这玩意,说实在一句话,比較难用,封装的不给力,最大缺陷例如以下:

1.不支持重定向,重定向须要自己来写,非常费事

2.新建的httpclient对象仅仅能发送同域名的请求

这相当的蛋疼,我花了一点时间封装了一下,攻克了上面的两个问题,还添加了自己主动编解码问题,代码例如以下:

#!/usr/bin/env python
#-*-encoding:UTF-8-*- import re
from geventhttpclient.url import URL
from geventhttpclient.client import HTTPClient,HTTPClientPool from urlparse import urljoin #from core.common import urljoin HEADERS = {
'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0'
} DEFAULF_METHOD = "GET"
MAX_REDIRECT_TIME = 10
DEFAULT_PAGE_ENCODING = "utf8" class DifferDomainException(Exception):
"""
if request different domain url,geventhttpclient will throw it,
see gevent.client 'raise ValueError("Invalid host in URL")'
"""
def __init__(self,uri):
self.args = uri
self.uri = uri class MaxRedirectException(Exception):
def __init__(self,response):
self.args = response
self.response = response class HTTP(HTTPClient):
def request(self,request_uri, method=DEFAULF_METHOD,body=b"", headers={},follow_redirect=True,redirects=MAX_REDIRECT_TIME):
if body and method == DEFAULF_METHOD:
method = "POST"
h = [ k.title() for k in headers.iterkeys() ]
headers.update(dict( [ (k,v) for k,v in HEADERS.iteritems() if k not in h ] ))
response = super(HTTP,self).request(method, request_uri, body, headers)
if follow_redirect and response.status_code in (301,302,303,307) and response.method in ("GET","POST"):
if redirects:
location = response.get('location') or response.get('content-location') or response.get('uri')
if location:
location = urljoin(request_uri,location)
if not location.startswith(self._base_url_string):
raise DifferDomainException(location)
return self.request(location, method, body, headers, follow_redirect,redirects-1)
else:
raise MaxRedirectException(response)
return response class HTTPPool(HTTPClientPool):
def get_client(self, url):
if not isinstance(url, URL):
url = URL(url)
client_key = url.host, url.port
try:
return self.clients[client_key]
except KeyError:
client = HTTP.from_url(url, **self.client_args)
self.clients[client_key] = client
return client _POLL = HTTPPool(network_timeout=100,connection_timeout=100) META_CHARSET_REGEX = re.compile(r'(?si)<head>.*<meta http-equiv="?content-type"?[^>]+charset=(?P<result>[^">]+).*</head>')
def decodePage(content,content_type):
httpCharset, metaCharset = None, None
if content_type and content_type.find("charset=") != -1:
httpCharset = content_type.split("charset=")[-1]
match = META_CHARSET_REGEX.search(content)
if match:
metaCharset = match.group('result')
print httpCharset,metaCharset
charset = httpCharset or metaCharset or DEFAULT_PAGE_ENCODING return content.decode(charset).encode(DEFAULT_PAGE_ENCODING) def request(request_uri, method=DEFAULF_METHOD,body=b"", headers={},follow_redirect=True,auto_read=True):
client = _POLL.get_client(request_uri)
response = None
try:
response = client.request(request_uri,method,body,headers,follow_redirect)
except DifferDomainException,e:
print "DifferDomainException:"+e.uri
response = request(e.uri,method,body,headers,follow_redirect)
except MaxRedirectException,e:
print "max redirect"
response = e.response # will return previous response,of course redirect response
except Exception,e:
print str(e) if auto_read and response:
with response:
response.content = decodePage(response.read(),response.get('content-type'))
return response def test():
# print request("http://127.0.0.1/re.php",follow_redirect=False)
# print request("http://127.0.0.1/re.php",follow_redirect=True).content
r=request("http://www.baidu.com/",follow_redirect=False)
#baidu utf8 utf8
print r.content[:10]
r=request("http://www.163.com/",follow_redirect=False)
#163 gbk gb2312
print r.content[:10] test()

在測试网页编码问题遇到了一些问题,看以下:

因为头部的请求先到,所以我们一般觉得返回的内容编码是先依据头部的,假设没有再看页面编码。

我们看网易的编码,头部为gbk,网页为gb2312,但用gb2312解码居然有问题,??? 我非常不解,各位大大们为啥呢?

但用头部gbk解码是正常的,这也证明了头部编码优先。按理说网页编码是告诉浏览器以gb2312显示,但明显有问题,浏览器怎么做到的?

我们再看新浪的,这更让我郁闷了,谁来解救我啊?

[Python网络编程]gevent httpclient以及网页编码的更多相关文章

  1. Python -- 网络编程 -- 简单抓取网页

    抓取网页: urllib.request.urlopen(url).read().decode('utf-8')  ---  (百度是utf-8,谷歌不是utf-8,也不是cp936,ascii也不行 ...

  2. 《Python网络编程》学习笔记--使用谷歌地理编码API获取一个JSON文档

    Foundations of Python Network Programing,Third Edition <python网络编程>,本书中的代码可在Github上搜索fopnp下载 本 ...

  3. Python网络编程基础 PDF 完整超清版|网盘链接内附提取码下载|

    点此获取下载地址提取码:y9u5 Python网络编程最好新手入门书籍!175个详细案例,事实胜于雄辩,Sockets.DNS.Web Service.FTP.Email.SMTP.POP.IMAP. ...

  4. Python 网络编程(一)

    Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

  5. Python学习(22)python网络编程

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

  6. Day07 - Python 网络编程 Socket

    1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...

  7. Python 网络编程相关知识学习

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

  8. python 网络编程 TCP/IP socket UDP

    TCP/IP简介 虽然大家现在对互联网很熟悉,但是计算机网络的出现比互联网要早很多. 计算机为了联网,就必须规定通信协议,早期的计算机网络,都是由各厂商自己规定一套协议,IBM.Apple和Micro ...

  9. python网络编程,通过服务名称和会话类型(tcp,udp)获取端口号,简单的异常处理

    作为一个php程序员,同时有对网络方面感兴趣,php就比较蛋疼了,所以就抽了些时间看python 之前学python基础因为工作原因,断断续续的看了个基础,差不多是可以写代码了 最近在看<pyt ...

随机推荐

  1. [每日一题] 11gOCP 1z0-052 :2013-09-5 runInstaller oracle of no swap

    转载请注明出处:http://blog.csdn.net/guoyjoe/article/details/11186995 正确答案:A 我们先来看下面这张截图,这是我在安装Oracle 11.2.0 ...

  2. VB.NET<机房收费系统个人重构版>你都学会了什么(之五)

    接着上篇我们说的配置文件,今天我们来说一下接口. 1.UML图 2.三层架构 3.Sqlhelper 4.配置文件 5.接口 6.设计模式 什么是接口呢?我们可以将接口理解为用于沟通的中介的抽象化.可 ...

  3. wamp环境中mysql更改root密码

    集成的wamp环境命令不好使,在phpmyadmin中更改密码 权限——root用户修改,执行 然后,你会发现你不能用phpmyadmin登陆了修改下phpmyadmin里面对应的密码就可以了将php ...

  4. heapq

    heapq-Guest-ChinaUnix博客 假设你需要维护一个列表,这个列表不断有新的元素加入,你需要在任何时候很方便的得到列表中的最大(小)值,因此要求列表始终处于排序完毕状态,怎么办呢 最简单 ...

  5. 基于SIFT+Kmeans+LDA的图片分类器的实现

    原地址:http://www.cnblogs.com/freedomshe/archive/2012/04/24/2468747.html 题记:2012年4月1日回到家,南大计算机研究僧复试以后,等 ...

  6. Powershell Mail module, 发送outbox 里的全部邮件(一个.csv文件代表一封邮件)

    把creating mail代码写到调用处,往outbox写入 mailxxx.csv文件,入面记录了邮件的主要内容 写入 #template $TMP = IMPORT-CSV "$($d ...

  7. GridView的RowDataBound事件中获取当前行内容的几种方法

    1. Cells[x].Txt.    从列单元格的文本值获取.这种方法简单高率,最为常用,但是功能单纯.此法存在几个缺点:   (1)无法获取到设置了隐藏属性的数据列的值,所取到的值为“”(空).  ...

  8. 使用WiX Toolset创建.NET程序发布Bootstrapper(安装策略管理)(一)——初识WiX

    原文:使用WiX Toolset创建.NET程序发布Bootstrapper(安装策略管理)(一)--初识WiX Visual Studio 打包安装七宗罪 开发.NET的人,肯定会使用Visual ...

  9. WPF-20:richtextbox相关操作(转)

    WPF中的richtextbox与winform中的richtextbox的使用不同,看看下面的基本操作: 一.取出richTextBox里面的内容  (1)将richTextBox的内容以字符串的形 ...

  10. svnkit添加节点

    package com.repositoryclient.svnoptions; import org.tmatesoft.svn.core.SVNException; import org.tmat ...