介绍:

网络爬虫的名字非常有意思,英文名称web spider。

真得非常形象。蜘蛛结网为了获取食物,而我们的爬虫程序,也是为了获取网络上的资源。

这篇blog是本人学习过程中的记录。学习过程中,使用的语言是python2.7;python2.7有两个模块,urllib和urllib2,这两个模块提供了非常好的网络訪问的功能。以下会更好的体会。值得一提的时,在python3中。将urllib和urllib2这两个模块合为一个urllib。感兴趣的能够看这里

urllib和urllib2是python中功能强大得网络工作库,它们让你的网络訪问像文件訪问一样(比如。文件訪问我们要先open()一个文件。它的操作也是类似的,后面就会看到样例)。之所以可以这么方便。由于这些模块的内部非常好的使用不同的网络协议来完毕这些功能,(学过网络应该了解,訪问一个网页这个简单的过程,事实上涉及到非常多的网络协议,像http。dns等等,而urllib和urllib2封装了这些协议。让我们不用和它们打交道,仅仅须要调用这些模块的方法来完毕我们须要的功能)。同一时候,这些模块也提供一些略微更复杂一点的借口来处理一些情形,比如用户认证,cookies和代理等等。

以下让我们開始来学习它们吧。

从简单语句中開始:

前面说过。使用两个模块,訪问网页变得就会像訪问文件一样方便。

在普通情况下。urllib2訪问会更好些(效率上更好,只是urllib还是须要使用,后面会介绍须要urllib做一些事情)。所以以下我们来看看使用urllib2的最简单的样例。

import urllib2;

response = urllib2.urlopen("http://www.zhonghuan.info");

html = response.read();

print html;

在终端下下输入命令行 python test.py > zhonghuan.html ,

打开文件后显示的是我的个人blog首页的html代码:

这是最简单的一个利用urllib2訪问网页的样例。urllib2是依据URL中:前面的部分来推断是用什么协议訪问的,比如,上面的样例我们用的时http,这里也能够换成ftp:,file:,等。。。

我们能够不用去了解它内部是怎样封装这些网络协议的。

urllib2中能够用一个镜像对象(Request Object)来表示我们http訪问,它标示你想要訪问的URL地址,我们来看一下以下的样例。

import urllib2

req = urllib2.Request('http://www.zhonghuan.info')

response = urllib2.urlopen(req)

the_page = response.read()

print(the_page)

req变量就是一个Request对象。它确切的标示了你要訪问的URL地址。

事实上。Request对象还能做两个额外的事情。

你能够发送数据给server。

你能够发送一些额外的信息(又叫元数据。描写叙述数据的数据。一些语言里面的元类是生成类的类,如python就在这些语言中;所以元数据,顾名思义。描写叙述数据的数据,那么这些被描写叙述的数据是什么呢?上面中,还有request对象的一些信息。而这些描写叙述被放在http头部发送出去了。有关http header,能够看这里);

传送数据给server

有时候,你须要发送数据给server,这个地址是URL表示的。通常呢。这个地址的指向是CGI(Common Gateway Interface)脚本或者是其他一些网络应用。(关于CGI脚本,能够看这里。简单的说就是处理上传数据的脚本程序)。

在HTTP訪问中。通常使用哪个POST方式将数据发送出去,就好像你填完了html中得表单,你须要把表单中得数据发送出去。通常这里使用post请求。当然,post使用还有其他的情况。不单单指的是表单这一种情况。

让我们先看以下的代码:

import urllib

import urllib2

url = 'http://www.someserver.com/cgi-bin/register.cgi'

values = {'name' : 'Michael Foord',

'location' : 'Northampton',

'language' : 'Python' }

data = urllib.urlencode(values) #数据须要又一次编码成合适的格式,这里使用的时urllib中得方法,由于urllib2中没有编码的方法

req = urllib2.Request(url, data) # #这里将须要上传的数据。传递给了equest对象,作为它的參数

response = urllib2.urlopen(req)

the_page = response.read()

关于其他类型的数据上传,能够看这里

除了使用post方式上传数据外,还能够使用get方式上传数据,get上传和post上传明显的差别就是get上传的数据会在URL中得尾部显示出来。

能够看以下的代码:

import urllib

import urllib2

data = {}

data['name'] = 'Somebody Here'

data['location'] = 'Northampton'

data['language'] = 'Python'

url_values = urllib.urlencode(data)

print url_values # 这里的顺序不一定

url = 'http://www.example.com/example.cgi'

full_url = url + '?' + url_values

data = urllib2.urlopen(full_url)

能够悄悄打印出来url_value的形式。

HTTP头—描写叙述数据的数据

如今。我们来讨论一下HTTP头。来看看怎样在你的HTTP的Request对象,添加一个HTTP头。

有一些站点,它比較智能,它不喜欢被程序訪问(非人为的点击仅仅会加重它server的负担)。

或者有些站点更加智能点。对于不同的浏览器,会发送不同的网页数据。

但是呢,urllib2默认,会这样标示自己,Python-urllib/x.y(当中。x和y各自是大小版本,比如我如今使用的时Python-urllib/2.7);而这些数据可能会让一些网站认为迷惑。要是遇上了不喜欢被程序訪问的网站,那么这种訪问可能会直接被忽视。

所以,你能够构造一些身份。让网站不会拒绝你。看以下的样例。

import urllib

import urllib2

url = 'http://www.someserver.com/cgi-bin/register.cgi'

user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' #user_agent用来标示你的浏览器的,向这里就是mozilla

values = {'name' : 'Michael Foord',

'location' : 'Northampton',

'language' : 'Python' }

headers = { 'User-Agent' : user_agent }

data = urllib.urlencode(values)

req = urllib2.Request(url, data, headers)

response = urllib2.urlopen(req)

the_page = response.read()

异常

异常时常有,要小心提防呐。想想一般文件操作的时候,会有什么异常呢?文件无法打开,什么权限不够啊。文件不存在啊等等异常。相同的。对于URL訪问。也会遇到这些问题,(python一些内部异常,比如ValueError,TypeError等异常。也可能会发生)

URLError

先说说URLError。当没有网络连接,或者訪问的server地址不存在的时候,在这样的情况下。URLError会被抛出来,这个时候,URLError异常会有个“reason”属性。它是一个元组。包括error code(int型)和text error message(string型),看以下的代码

import urllib

import urllib2

req = urllib2.Request('http://www.pretend_server.org')

try: urllib2.urlopen(req)

except urllib2.URLError as e:

print e.reason

输出[Errno 8] nodename nor servname provided, or not known;输出的内容就是reason。

HTTPError

每个HTTP訪问,会从server那儿获得一个“status code”(状态码)。通常这些状态码告诉我们server无法满足一些訪问(直白点说就是一些数据而已,仅仅只是表示的是当前訪问的状态,比方当前訪问被拒绝了,status code能够告诉你,你哪些举动过分了。出格了。注意,咸猪手不能够有啊~~)。

只是呢,urllib2的默认处理器可以帮助你处理一些server的响应,比方说你当前訪问的网址被server重定向了,就是说你的server给你一个新的URL訪问了,处理器会帮你直接去訪问新的URL。

可是默认的处理器毕竟功能有限。它不能帮助你解决全部问题。比方你訪问的站点不存在了(相应404错误。我们有时候会看到这个错误),或者你的訪问被禁止了(相应403错误,禁止的原因可能是由于你的权限不够啦等等),又或者是须要你验证啦(相应401)。详细的其他错误本文就不介绍啦,详细能够看这里

让我们看以下的程序,看一下当HTTPError的404错误,也就是页面不存在时候。它会输出点什么。

import urllib

import urllib2

req = urllib2.Request('http://www.zhonghuan.info/no_way')

try: urllib2.urlopen(req)

except urllib2.HTTPError as e:

print e.code;

print e.read();

输出:

404

Page not found · GitHub Pages

处理异常

如果你想要捕捉HTTPError和URLError,有两种主要的方法。推荐另外一种噢!

第一种:

from urllib2 import Request, urlopen, URLError, HTTPError

req = Request(http://zhonghuan.info)

try:

response = urlopen(req)

except HTTPError as e:

print 'The server couldn\'t fulfill the request.'

print 'Error code: ', e.code

except URLError as e:

print 'We failed to reach a server.'

print 'Reason: ', e.reason

else:

# everything is fine

第一种方法。HTTPError一定要放在URLError前面,原因呢,和非常多语言的异常处理机制一样,HTTPError是URLError的子类,假设发生了HTTPError。它能够被当做是URLError被捕捉。

另外一种:

from urllib2 import Request, urlopen, URLError

req = Request(someurl)

try:

response = urlopen(req)

except URLError as e:

if hasattr(e, 'reason'):

print 'We failed to reach a server.'

print 'Reason: ', e.reason

elif hasattr(e, 'code'):

print 'The server couldn\'t fulfill the request.'

print 'Error code: ', e.code

else:

# everything is fine

info和geturl

这里介绍两个方法info()和geturl();

geturl():该方法会返回訪问的页面的真实的URL,它的价值在于我们訪问的网页可能会被重定向,所以导致訪问的URL和我们输入的可能不一样。看以下的样例:

import urllib

import urllib2

url = 'http://weibo.com/u/2103243911';

req = urllib2.Request(url);

response = urllib2.urlopen(req)

print "URL:",url;

print "After redirection:",response.geturl();

以我的微博个人主页为例,事实上真实訪问被重定向了,真实的网址,从输出中能够看出:

URL: http://weibo.com/u/2103243911

After redirection: http://passport.weibo.com/visitor/visitor?

a=enter&url=http%3A%2F%2Fweibo.com%2Fu%2F2103243911&_rand=1409761358.1794

info():能够得到描写叙述页面的信息,返回的是一个httplib.HTTPMessage实例,打印出来非常像字典。

看以下的代码:

import urllib

import urllib2

url = 'http://zhonghuan.info';

req = urllib2.Request(url);

response = urllib2.urlopen(req);

print response.info();

print response.info().__class__;

输出:

Server: GitHub.com

Content-Type: text/html; charset=utf-8

Last-Modified: Tue, 02 Sep 2014 17:01:39 GMT

Expires: Wed, 03 Sep 2014 15:23:02 GMT

Cache-Control: max-age=600

Content-Length: 4784

Accept-Ranges: bytes

Date: Wed, 03 Sep 2014 16:38:29 GMT

Via: 1.1 varnish

Age: 5127

Connection: close

X-Served-By: cache-lax1433-LAX

X-Cache: HIT

X-Cache-Hits: 1

X-Timer: S1409762309.465760,VS0,VE0

Vary: Accept-Encoding

Class: httplib.HTTPMessage

Opener和Handler

这里介绍Opener和Handler。

什么是Opener呢?事实上上面的样例我们一直在用Opener了,就是urlopen。这个是默认的opener。网络訪问情况非常多,你能够创建比較合适的opener,

什么是Handler呢?事实上Opener会调用Handler来处理訪问中得琐事,所以Handler非常重要,对于特定的协议(比如FTP,HTTP)。它知道怎样怎样处理訪问。比如它会帮你处理重定向问题。

在訪问的时候。你可能对于Opener有一些要求,比如,你希望得到的Opener可以处理cookie,或者你不希望Opener帮助你处理重定向。

我们怎样生成须要得Opener呢?(这里插一下,个人认为这里的Opener生成方式,和设计模式中得生成器欧式,又叫建造者模式,英文名称Builder Pattern;有些相似,只是不全然一样,但总认为,在看下去之前。先了解一下这个模式会有优点。没有接触过的朋友能够看这篇Builder

pattern);

要创建一个 opener,能够实例化一个OpenerDirector,

然后调用.add_handler(some_handler_instance)。

只是,能够使用build_opener。这是一个更加方便的函数,用来创建opener对象,他仅仅须要一次函数调用。build_opener默认加入几个处理器,但提供快捷的方法来加入或更新默认处理器。

其它的处理器handlers你也许会希望处理代理,验证,和其它经常使用但有点特殊的情况。

刚刚提到handler会帮我们处理重定向,可是。假设我们不想要重定向呢,该怎么办,自己定义一个handler。

看以下的代码:

mport urllib

import urllib2

class RedirectHandler(urllib2.HTTPRedirectHandler):# 这个RedirectHandler继承了HTTPRedirectHandler,只是,它覆盖了父类的方法,让它什么都不做。失去了重定向的功能。

def http_error_301(self, req, fp, code, msg, headers):

pass

def http_error_302(self, req, fp, code, msg, headers):

pass

webo = "http://weibo.com/u/2103243911"; #訪问的是我的微博页面,由于正常情况下,訪问时会发生重定向

opener = urllib2.build_opener(RedirectHandler) #这里,我们自己定义了一个opener,加入了一个重定向时处理的自己定义handler

response = opener.open(webo);# response = urllib2.urlopen(webo);

print response.geturl();

urllib2.install_opener(opener); #安装自己定义的opener,以后调用urllib2的时候,返回的就是这个opener。

输出结果是:

urllib2.HTTPError: HTTP Error 302: Moved Temporarily

之所以发生http error 302,是由于本来訪问我的微博个人主页的时候。它应该发生重定向的,但是我们自己的重定向Handler什么都不做,结果就是发生异常了。

能够看看以下的urllib2关于创建自己定义Opener的类图

Basic Authentication

假设一个站点。他提供注冊登入这些功能。那么一般它实username/password,假设你訪问的页面,系统要求你提供username/password,这个过程叫做Authentication,实在server那端所做的操作。它给一些页面提供了安全保护。

一个主要的Authentication(验证)过程是这种:

client提出请求訪问某些页面。

server返回一个错误,要求进行身份验证。

client把username/password(一般这样)编码后发给server。

server检查这对username/password是否正确,然后返回用户请求的页面或者是一些错误。

上面的过程。还有可能是其他形式,这里仅仅是举个比較普遍的。

通常server返回的是401错误,表明訪问的网页未授权。同一时候。返回的response的header内有形如

WWW-Authenticate: SCHEME realm="REALM".

的内容,比如,你想要訪问cPanel的管理应用程序,你会收到这种header:WWW-Authenticate: Basic realm="cPanel"(cPanel 是一套在网页寄存业中最享负盛名的商业软件。其基于 Linux 和 BSD 系统及以 PHP 开发且性质为闭源软件;cPanel 主要是面向客户权级的控制系统)

当我们訪问页面的时候,opener会调用handler来处理各种情况。而处理Authentication的handler是urllib2.HTTPBasicAuthHandler。同一时候须要一个用户password管理器urllib2.HTTPPasswordMgr。

不幸的时。HTTPPasswordMgr有一个小问题,就是在获取网页前,你须要知道它的realm。幸运的是,它有一个表兄弟HTTPPasswordMgrWithDefaultRealm,这个表兄弟能够事先不知道realm,在realm參数位置上,能够传一个None进去。它更友好的被使用。

以下參考以下的代码:

import urllib2

url = 'http://www.weibo.com'#分别相应域名,账号。密码

username = 'zhonghuan'

password = 'forget_it'

passman = urllib2.HTTPPasswordMgrWithDefaultRealm() #创建密码管理器

passman.add_password(None, url, username, password)# 參数形式(realm,URL,UserName,Password)

authhandler = urllib2.HTTPBasicAuthHandler(passman)#创建Authentication的handler

opener = urllib2.build_opener(authhandler)

urllib2.install_opener(opener) #和上面介绍的一样。install_opener后,每次调用urllib2的urlopen,返回的就是这个opener

pagehandle = urllib2.urlopen(url)

代理

有时候,我们本机不能直接訪问,须要代理server去訪问。urllib2对这个设置代理支持的还不错,能够直接实例化ProxyHandler,它的參数是一个map,key值是代理的訪问协议名称,value值是代理的地址。看以下的代码实现。

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)

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)

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

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')

參考资料:

python网络爬虫学习_python网络爬虫学习笔记相关推荐

  1. python sub 不区分大小写_Python网络爬虫入门篇

    1. 预备知识 学习者需要预先掌握Python的数字类型.字符串类型.分支.循环.函数.列表类型.字典类型.文件和第三方库使用等概念和编程方法. Python入门篇:https://www.cnblo ...

  2. python 爬虫框架_Python网络爬虫-scrapy框架的使用

    1. Scrapy 1.1 Scrapy框架的安装 Scrapy是一个十分强大的爬虫框架,依赖的库比较多,至少需要依赖的库有Twisted .lxml和pyOpenSSL.在不同的平台环境下,它所依赖 ...

  3. python 爬虫论_Python网络爬虫(理论篇)

    欢迎关注公众号:Python爬虫数据分析挖掘,回复[开源源码]免费获取更多开源项目源码 网络爬虫的组成 网络爬虫由控制节点,爬虫节点,资源库构成. 网络爬虫的控制节点和爬虫节点的结构关系 控制节点(爬 ...

  4. python网络爬虫应用_python网络爬虫应用实战

    原标题:python网络爬虫应用实战 Python这门编程语言包罗万象,可以说掌握了python,除了一些特殊环境和高度的性能要求,你可以用它做任何事. Python作为一门脚本语言,它灵活.易用.易 ...

  5. python网络爬虫应用_Python网络爬虫(requests模块应用1)

    一.什么是requests模块? requests模块是python中原生的基于网络请求的模块,其主要作用是用来模拟浏览器发起请求.功能强大,用法简洁高效.在爬虫领域中占据着半壁江山的地位. 二.为什 ...

  6. python爬虫数据挖掘_Python网页爬虫文本处理科学计算机器学习数据挖掘兵器谱...

    转载自"我爱自然语言处理":http://www.52nlp.cn,已获得授权.更多内容可见公众号:"牛衣古柳"(ID:Deserts-X). 周末时看到这篇不 ...

  7. python基础教程知识点_Python基础教程学习应该掌握的知识点总结

    很多人都想要Python的入门方法以及知识,参加Pythone培训班的同学也不例外.那么今天小编就来给大家分享一下零基础学习Python应该掌握的知识点总结. Python基础教程与高级编程 1.Li ...

  8. python开发网络小工具_python 网络工具

    书籍:掌握Python的网络和安全 Mastering Python for Networking and Security - 2018.pdf 简介 掌握Python的网络和安全 掌握Python ...

  9. python网络编程项目_python网络编程详解

    最近在看<UNIX网络编程 卷1>和<FREEBSD操作系统设计与实现>这两本书,我重点关注了TCP协议相关的内容,结合自己后台开发的经验,写下这篇文章,一方面是为了帮助有需要 ...

最新文章

  1. java jar log4j_使用Log4j
  2. 我的Android进阶之旅------gt;Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题...
  3. 网络爬虫终篇:向10万级网易云用户发送定向消息
  4. Ehcache介绍及整合Spring实现高速缓存
  5. node ajax validator,使用validator.js对字符串数据进行验证
  6. ora-24247:网络访问被访问控制列表(ACL)拒绝
  7. java大数据组件HBase
  8. 图像处理--知识点整理
  9. android调用邮件应用发送email
  10. groupmod 修改用户组信息
  11. 什么是 Python 编程语言?
  12. 用python分析世界各国的 “幸福指数”。
  13. java图片转换pdf_Java将图片转化为PDF的方法(1)
  14. vue.js解析lrc格式歌词文件
  15. javascript写的一个练习打字的小程序
  16. zmq pub/sub使用详解
  17. 火爆科研圈的三维重建技术:Neural radiance fields (NeRF)
  18. 笔记本硬盘读取测试软件,电脑硬盘怎样检测 电脑硬盘故障检测软件【详解】...
  19. Linux shell计算两个文件的交集,并集和差集
  20. endNote X9 导入英文文献(谷歌学术、web of science 等)

热门文章

  1. 基于 PyTorch 的 cifar-10 图像分类
  2. 【DevCloud · 敏捷智库】软件开发团队如何管理琐碎、突发性任务(内附下载材料)
  3. linux tail 命令详解,Linux下如何使用tail命令指南
  4. 现代密码学导论-2-古典密码及其密码分析
  5. 计算机软件的安装步骤及注意事项,组态软件介绍以及安装注意事项
  6. 入门MSP430FR6989 第一章
  7. 利用遗传算法进行高频因子挖掘(一)
  8. Ubuntu的端口占用问题
  9. 个人开发者如何通过Android应用赚外快
  10. css水平垂直居中(不定高)的三种方法