Python网络爬虫<Web Scraping With Python-----O‘Reilly>

来源:互联网 发布:淘宝网小额贷款 编辑:程序博客网 时间:2024/06/05 16:45

学习Python网络爬虫,一直没有什么很好的书籍来看。在网上发现了这本Web Scraping With Python-----O‘Reilly的英文版,无奈没有发现中文翻译。所以,趁着假期无事尝试翻译出来当是一次特别的学习过程,也希望拿出来给需要的人一些小小的帮助。这是翻译的第一章,后续章节会陆续翻译。第一次翻译必有很多不足之处,语言牵强附会,词不达意等情况希望大家多包涵。如果有侵权行为请及时告知,会及时删除处理。

--------2015年7月21日

Chapter 1.

你的第一个网络爬虫

一旦你开始网页爬虫,你会开始感激浏览器为我们做的所有小事。这个网页,没有一层HTML格式,CSS样式,JavaScript执行和图片渲染,第一眼看起来有点惊人,但是在这一章,以及下一章,我们将讨论如何在没有浏览器的情况下格式化和解析数据。这一章将会开始于向浏览器的特定页面发送一个GET请求这样的基础知识,读取该页面的HTML输出,并且做一些简单的数据提取,分离出我们要找寻的数据。

连接:

如果你没有在网络或者网络安全方面有过多了解,那么互联网的机制看起来就有点神秘。我们不想去考虑在网络中当我们打开一个浏览器并且打开http://google.com究竟是什么,而且对于这些,我们并不需要去了解。事实上,我认为它最伟大的地方是计算机接口有着高级的一点是不管任何人在任何地点使用网络对于他如何工作是没有一丝任何的想法的。然而,网络爬虫需要剥离一些这方面外壳的接口,不仅仅是在浏览器的层次(它如何解释了这些HTML,CSS和JavaScript),而是偶尔的网络连接方面。为了让你了解一下你的浏览器获取所需信息的基本过程,我们用下面的例子说明一下。

爱丽丝拥有一个Web服务器,Bob使用一个台式电脑去尝试连接爱丽丝的服务器。当一台机器想要和另外一台机器交流时,会产生类似于下面的这种交换:

1、Bob的电脑沿着比特流发送了1和0的高低电压,这些比特组成了一些信息,包含一个报头和报文。报头包含Bob的路由器的MAC地址为直接目的地址,爱丽丝的IP为最终目的地址。报文包含了请求爱丽丝服务器的应用程序。

2、Bob的本地路由器接收所有这些1和0,并封装他们作为一个包,从Bob自身的MAC地址,发往爱丽丝的IP地址。他的路由器标记他的IP在包中作为“来自”的IP,并且把他通过网络发送出去。

3、Bob的包经过多个中间服务器来给他的包指向通往爱丽丝服务器的正确的物理地址和有

线的路径。

4、爱丽丝的服务器收到这个包和她的IP地址。

5、爱丽丝的服务器读取这个包中位于报头的的端口地址(几乎所有的web端口都是80(默认80端口),这可以被认为是类似于包数据的“公寓号”,IP地址就是“街道地址”),并且通过他关闭相应的应用程序——Web服务器应用程序

6、Web服务器应用程序从服务器处理器接收到流数据。这个数据说是这样的:

-这是一个GET请求

-接下来是文件要求:index.html

7、Web服务器找到正确的HTML文件,封装到一个新的包中通过本地路由器发送给Bob,通过相同的过程,传输给Bob的电脑看。

我们有互联网!

所以,在这个交流中浏览器起到了什么作用呢?绝对没有地方用到事实上,在互联网历史中浏览器还是一个相对较新的发明。当时的Nexus发布于1990年。当然,浏览器是一个在创建这些信息包方面非常有用的应用,发送这些包,解析你回收到的数据,比如漂亮的图片,声音,视频以及文字。然而,浏览器只是一些代码,这些代码可以被拆分,分解成它最基本的组成部分,可以被重新写,重新使用,可以用来做我们想做的任何事情。一个Web浏览器可以告诉处理器可以给无线(有线)应用的接口发送一些数据,但是大多数编程语言有能够做好这些的库。让我们看看python中是如何工作的:

form urllib.request import urlopen

html = urlopen("http://pythonscraping.com/pages/page1.html")

print(html.read())

你可以已scrapetest.py保存这些代码并且在终端里用如下命令运行:

$python3 scrapetest.py

这将输出http://pythonscraping.com/pages/page1.html页面完整的HTML代码。更准确的说,输出的是HTML文件的page.html1,这个文件建立在位于域名http://pythonscraping.com的<网络根结点>/页面目录中。

这两者有什么不同呢?大多数的现代网页都有大量的与网页相关联的资源文件。这些可能是图像文件,JavaScript文件,CSS文件,或者其他你可以请求链接到的页面。当Web浏览器访问一个页面标签,如<imgscr="cutekitten.jpg">,为了将页面完全呈现给用户,浏览器知道这个需要使用另外一个请求访问服务器的cuteKitten.jpg文件去获取数据。请记住这一点,我们的Pyhton脚本没有返回并且请求多种文件的逻辑;它只能读取到我们所请求的单一HTML界面。

所以他是如何做到这一点的呢?要感激Python的纯英语性质:这一行

from urllib.request import urlopen

的意思就如同看到的一样:在Python的request模块(建立在urllib库)中仅仅导入urlopen函数。

选择urllib还是urllib2?

如果你在Python2.x中使用过urllib2,你会注意到在urllib2和urllib之间发生了一些变化,在Python3.x中,urllib2被重命名为urllib并且分割成一些子模块:urllib.request, urllib.parse, 和urllib.error。但是函数名称大多保持相同,当使用新的urllib库时,你需要注意哪个函数已经被移动到子模块中。

urllib是一个Python的标准库(这意味着运行这个例子的时候你不需要安装任何额外的东西)并且包含了在网络上请求数据,处理cookies,甚至于改变如同头和用户代理这些元数据。我们将在本书中从头到尾的使用urllib,所以我们建议你去阅读Python文档中的这个库。

urllopen用于打开一个不同网络的远程对象并且读取出来。因为它是一个相当通用的一个库(它可以轻松的读取HTML文件,读取图像文件以及其他任何文件流),我们将会相当频繁的在书中使用。

BeautifulSoup的简介:

“美丽的汤,如此丰富和有生机,

在滚烫的盖碗中等待!

谁面对这样的美味不会自甘堕落?

晚安,汤,美丽的汤!”

这个BeautifulSoup模块被命名为爱丽丝梦游仙境中的Lewis Carroll的同名诗歌。在故事中,这首诗是一个叫做素甲鱼(本身对流行的维多利亚素甲鱼汤制成的双关语,但是不是甲鱼是牛)的人物唱的就像它同名的仙境,BeautifulSoup试图让它没有意义感,它通过处理糟糕的HTML和呈现给我们简单的找寻Python对象代表的XML结构来帮助我们格式化和组织混乱的网页。

安装BeautifulSoup:

由于BeautifulSoup模块不是Python默认库,它需要安装使用。在这本书中我们将会使用BeautifulSoup4库(又名BS4)。完整的安装介绍可以在Crummy.com找到;

不过,对于linux的基本安装方法是:

$sudo apt-get install python-bs4

以及对Macs:

$sudo easy_install pip

这个安装了Python的pip工具包,然后运行以下命令:

$pip insatall beautifulsoup4

来安装库。

接下来,注意你是否在机器上同时安装了Python2.x和Python3.x,如果是,那么你需要显式的调用python3:

$python3 myScript.py

当安装包之后也通过这样确认,也许包被安装在Python2.x而不是Python3.x:

$sudo python3 setup.py install

如果使用pip,你可以使用pip3去安装Python 3.x版本的包:

$pip3 install beautifulsoup4

在windows下安装包和Mac和Linux下安装过程基本相同。从下载链接上,下载最新的Beautifulsoup发行版,进入到你的解压目录,然后运行:

>python setup.py install

就是这样!BeautifulSoup现在被确认为你机器上的一个Python库。你可以通过打开一个Python终端导入测试一下:

$python

>from bs4 import BeautifulSoup

这个导入应该完全没有错误。此外,在windows中还有一个对于pip的.exe安装方式,所以你可以轻易的安装和管理包:

>pip install beautifulsoup4

让库直接运行在虚拟环境中

如果你打算处理多个Python项目或者需要一种能够方便的捆绑和项目相关的所有库,或者

你担心安装的库之间存在潜在的冲突,你可以安装一个Python虚拟环境去把所有的去分离

开,并且易于管理:

$virtualenv scrapingEnv

这个命令创建了一个叫做scrapingEnv的新环境,你需要去激活使用:

$cd acrapingEnv/

$source bin/activate

在你激活了环境之后,你将会看到这个环境的名称在命令提示行提醒你,提醒你当前的工作。你安装的任何库和你运行的任何脚本都仅仅在这个虚拟环境上。工作在新创建的scrapingEnv环境中,我可以安装使用BeautifulSoup,例如:

(scrapingEnv)ryan$ pip install beautifulsoup4

(scrapingEnv)ryan$ python

>from bs4 import BeautifulSoup

>

我可以通过解除命令离开这个环境,离开之后就不能访问任何我安装在虚拟环境中的库:

(scrapingEnv)ryan$ deactivate

ryan$ python

>from bs4 import BeautifulSoup

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

ImportError: No module named 'bs4'

使项目的库分离可以很容易的压缩整个环境发送给其他人。只要他们的机器中安装有相同版本的Python,你的代码就可以工作在虚拟环境中而不需要他们安装任何库。尽管我们没有明确的指出你去在虚拟环境中使用本书的例子,请记住,你可以预先激活虚拟环境并在任何时候简单的使用。

运行BeautifulSoup:

在BeautifuSoup中最常用的一个对象就是,这个BeautifulSoup对象。让我们在使用中看一下,修改本章开始建立的例子:

from urllib.request import urlopen

from bs4 import BeautifulSoup

html = urlopen("http://www.pythonscraping.com/exercises/exercises1.html")

bsObj = BeautifulSoup(html.read())

print(bsObj.h1)

这个输出就是:

<h1>An Interesting Title</h1>

在这个例子之前,我们导入了urlopen库并且调用了html.read()去获取HTML页面的内容。这个HTML内容然后被转换成一个BeautifulSoup对象,类似以下的结构:

html →<html><head>...</head><body>...</body></html>

head →<head><title>A Useful Page</title></head>

tile → <title>A Useful Page</title>

body →<body><h1>An Int...</h1><div>Lorem ip...</div></body>

h1 → <h1>An Interesting Title</h1>

div → <div>Lorem Ipsum dolor...</div>

需要注意的是,我们从页面提取的<h1>标签嵌套了两层深入到了BeautifulSoup对象中 (html → body → h1)。然而,当我们真正的从对象获取的话,我们直接调用h1标签:

bsObj.h1

事实上,任何以下函数调用都可以提供相同的输出:

bsObj.html.body.h1

bsObj.body.h1

bsObj.h1

我们希望这个小味道的BeautifulSoup库可以通过权限给你一个想法去简化这个库。实质上任何信息都可以从任何HTML(或者XML)中被提取出来,只要它有可以辨认的标签包围,或者接近。在第三章中,我们会更深入的钻研一些更复杂的BeautifulSoup函数调用,以及看一看正则表达式,已经他们如何与BeautifulSoup共同使用提取网页信息。

可靠的连接:

一个混乱的网页:数据格式不合理,网站继续看下去,结束标签也失踪了。在网页爬虫中,最令人沮丧的经历就是当你开始运行爬虫然后去睡觉,想着第二天会得到所要的所有数据——只发现了爬虫撞上了一个没有预料到的数据格式异常,在你走开不久就停止了执行。在这样的情况下,你可能会尝试去诅咒这个网站的开发者(和格式奇怪的数据),但是,你真正应该踢的是自己的屁股,对于没有第一时间预料到这个异常。让我们看一下我们爬虫的第一行,在导入语句之后,来指出如何处理可能抛出的异常:

html = urlopen("http://www.pythonscraping.com/exercises/exercises1.html")

在这一行有两个主要的事情会产生错误:

①页面在服务器上没有被找到(或者在检索的时候发生了一些错误)

②服务器没有找到

在第一种情况中,将会返回一个HTTP异常。这个HTTP异常也许是“404页面未找到”,“500内部服务器错误”等。在这些所有的情况中,urlopen函数将会抛出"HTTPError"这个一般异常,我们可以通过下面的方法处理这个异常:

try:

html = urlopen("http://www.pythonscraping.com/exercises/exercise1.html")

except HTTPError as e:

print(e)

#返回Null,break或者做其他的“计划B”

else:

#程序继续,注意:如果你异常捕获中return或者break,就不需要这个“else”语句

如果返回一个HTTP异常,这个程序现在输出这个异常,并且不会执行这个代码下else语句的剩余部分。如果没有找到服务器,(如果说,http://www.pythonscraping.com这个服务器Down掉了或者网址输入错误了),urlopen函数返回一个None对象。这个对象类似于其他编程语言中的NULL。我们可以添加一个检查,看看是否返回的html是None:

if html is None:

print("URL is not found")

else:

#程序继续

当然,如果页面从服务器检索成功,这里依旧有一个问题就是,这个页面中并不是我们完全期望的内容。任何时候,你都可以在BeautifulSoup对象中访问一个标签,这是一个可以灵巧的检查确认表卡是否确实存在的办法。如果你尝试访问一个不存在的标签,BeautifulSoup将会返回一个None对象。问题在于,尝试去访问一个None标签时候将会导致一个AttributeError被抛出。下面一行(nonExistentTag是一个虚构的标签,不是一个真的BeautifulSoup函数)

print(bsObj.nonExistentTag)

返回一个None对象。这是个完美合理的处理检查对象。如果你不去检查他,而是在这个None对象上去尝试调用其它函数,麻烦就会来了,就像下面的情况:

print(bsObj.nonExistentTag.someTag)

这个会返回异常:

AttributeError:'NoneType'object has no attribute 'sometTag'

所以,如何才能防止出现这两种情况?最简单的方法是显式的检查这两种情况:

try:

badContent = bsObj.nonExistingTag.anotherTag

except AttributeError as e:

print("Tag was not found")

else:

if badContent == None:

print("Tag was not found")

else:

print(badContent)

第一眼看起来这种检查和处理每一个异常似乎很费力,但是这使得很容易重组代码让代码写起来少点困难(更重要的是读起来更清晰)。例如这个代码,是我们在写同一个爬虫时略微有一些不同的方式:

from urllib.request import urlopen

from urllib.error import HTTPError

from bs4 import BeautifulSoup

def getTitle(url):

try:

html = urlopen(url)

except HTTPError as e:

return None

try:

bsObj = BeautifulSoup(html.read())

title = bsObj.body.h1

except AttributeError as e:

return None

return title

title = getTitle("http://www.pythonscraping.com/exercises/exercise1.html")

if title == None:

print("Title could not be found")

else:

print(title)

在这里例子中,我们创建了一个getTitel函数,将会返回页面的任一Title,或者在提取时候有一些问题,返回一个None对象。里面的getTitle函数,我们用来检查HTTPError,因为在前面的例子中,也封装了两个包括了一个try方法的BeautifulSoup语句。在这几行中一个AttributeError也许会被抛出(如果服务器不存在,html会是一个None对象,所以html.read()将会抛出一个AttributeError)。事实上,我们可以在一个try语句中包含很多行,或者完全调用其他函数,从而可以在任何地点抛出一个AttributeError。当写爬虫时候,重要的一点就是在总体格局上同时考虑代码的异常处理和可读性。你可能会很希望可以重用大量的代码。具有通用功能的函数,比如:获取网站的HTML和getTitle(完整详细的异常处理),使得爬取网页非常的快速和可靠。

--------2015年7月21日

转载请注明出处http://blog.csdn.net/qq_15297487
1 0
原创粉丝点击