1.1python初入网络爬虫-网络连接和BeautifulSoup库的使用

一,网络连接

一旦你开始采集网络数据,就会感受到浏览器为我们做的所有细节。网络上如果没有HTML 文本格式层、CSS 样式层、JavaScript 执行层和图像渲染层,乍看起来会有点儿吓人,但接下来的内容,我们将介绍如何不通过浏览器的帮助来格式化和理解数据。

1.网络连接的过程

在现在智能化,自动化和数据化的时代,每当打开浏览器连接https://www.baidu.com 的时候,我们不会思考网络正在做什么, 而且如今也不必思考。实际上,我认为很神奇的是,计算机接口已经如此先进,让大多数 人上网的时候完全不思考网络是如何工作的。 但是,网络数据采集需要抛开一些接口的遮挡,不仅是在浏览器层(它如何解释所有的 HTML、CSS 和 JavaScript),有时也包括网络连接层。 我们通过下面的例子让你对浏览器获取信息的过程有一个基本的认识。
李红有一台网络 服务器。张三有一个台式机正准备连接 李红的服务器。当一台机器想与另一台机器对话 时,下面的某个行为将会发生。
1. 张三 的电脑发送一串 1 和 0 比特值,表示电路上的高低电压(类似于数电知识)。这些比特构成了一种信 息,包括请求头和消息体。请求头包含当前 张三 的本地路由器 MAC 地址和 李红的 IP地址。消息体包含张三 对 李红服务器应用的请求。
2.张三 的本地路由器收到所有 1 和 0 比特值,把它们理解成一个数据包(packet),从 张三 自己的 MAC 地址“寄到”李红 的 IP 地址。他的路由器把数据包“盖上”自己的 IP 地 址作为“发件”地址,然后通过互联网发出去。
3. 张三 的数据包游历了一些中介服务器,沿着正确的物理 / 电路路径前进,到了 李红 的 服务器。
4. 李红的服务器在她的 IP 地址收到了数据包。
5. 李红 的服务器读取数据包请求头里的目标端口(通常是网络应用的 80 端口,可以理解 成数据包的“房间号”,IP 地址就是“街道地址”),然后把它传递到对应的应用——网 络服务器应用上。
6. 网络服务器应用从服务器处理器收到一串数据,数据是这样的:
♦ 这是一个 GET 请求
♦ 请求文件 index.html
7. 网络服务器应用找到对应的 HTML 文件,把它打包成一个新的数据包发送给 张三,然 后通过它的本地路由器发出去,用同样的过程回传到张三 的机器上。
互联网就是那么一回事。 那么,在这场数据交换中,完全没有参与。
其实,在互联 网的历史中,浏览器是一个比较年轻的发明,始于 1990 年的 Nexus 浏览器。 的确,网络浏览器是一个非常有用的应用,它创建信息的数据包,发送它们,然后把你获 取的数据解释成漂亮的图像、声音、视频和文字。但是,网络浏览器就是代码,而代码是 可以分解的,可以分解成许多基本组件,可重写、重用,以及做成我们想要的任何东西。 网络浏览器可以让服务器发送一些数据,到那些对接无线(或有线)网络接口的应用上, 但是许多语言也都有实现这些功能的库文件。

2.python实现的网络连接功能

注:以后的实例代码可以使用python自带的IDLE解释器(python3)文件编写并运行,或者在pycharm上运行,因为都是比较新的,所以大部分代码都没什么运行问题。
http://pythonscraping.com/pages/page1.html是实例网站,现在使用该网址作为示例,希望大家不要恶意爬取和访问。

from urllib.request import urlopen
html=urlopen("http://pythonscraping.com/pages/page1.html")
print(html.read())

输出效果:
在这里插入图片描述
这将会输出https://python123.io/ws/demo.html这个网页的全部 HTML 代码。更 准确地说,这会输出在域名为 https://python123.io的服务器上 < 网络应用根地址 >/ ws 文件夹里的 HTML 文件 demo.html 的源代码。 有什么区别?现在大多数网页需要加载许多相关的资源文件。可能是图像文件、JavaScript 文件、CSS 文件,或你需要连接的其他各种网页内容。当网络浏览器遇到一个标签时,比 如 ,会向服务器发起另一个请求,以获取 cuteKitten.jpg 文件 中的数据为用户充分渲染网页。但是,我们的 Python 程序没有返回并向服务器请求多个文 件的逻辑,它只能读取我们已经请求的单个 HTML 文件。
注意:urllib 还是 urllib2 ?
如果你用过 Python 2.x 里的 urllib2 库,可能会发现 urllib2 与 urllib 有些不同。 在 Python 3.x 里,urllib2 改名为 urllib,被分成一些子模块:urllib.request、 urllib.parse 和 urllib.error。尽管函数名称大多和原来一样,但是在用新 的 urllib 库时需要注意哪些函数被移动到子模块里了。
urllib 是 Python 的标准库之一(就是说你不用额外安装就可以运行这个例子),包含了从网络请求数据,处理 cookie,甚至改变像请求头和用户代理这些元数据的函数。当然,以后所使用的request库也是个不错的选择!
urlopen 用来打开并读取一个从网络获取的远程对象。因为它是一个非常通用的库中函数(它可 以轻松读取 HTML 文件、图像文件,或其他任何文件流),所以我们将在以后的内容频繁地使 用它。

3.拓展:

Python3中urlopen()详解

二,BeautifulSoup简介

“美味的汤,绿色的浓汤,
在热气腾腾的盖碗里装!
谁不愿意尝一尝,这样的好汤?
晚餐用的汤,美味的汤!”
BeautifulSoup 库的名字取自刘易斯·卡罗尔在《爱丽丝梦游仙境》里的同名诗歌。
就像它在仙境中的说法一样,BeautifulSoup 尝试化平淡为神奇。它通过定位 HTML 标签来 格式化和组织复杂的网络信息,用简单易用的 Python 对象为我们展现 XML 结构信息。
相关介绍可以自行百度或CSDN博客搜索。

1.安装BeautifulSoup库

由于 BeautifulSoup 库不是 Python 标准库,因此需要单独安装。推荐python的pip工具进行安装,或在pycharm上安装虚拟环境从而来安装。
注意:引用时格式(from bs4 import BeautifulSoup),但通过pip安装时,是beautifulsoup4,注意单词中大小写的不一样。
以Windows平台上pip工具的安装为例:
以管理员权限打开终端命令行:
输入:

pip install beautifulsoup4

即可自动下载并安装,安装成功会有提示!
安装成功后,查询并确认相关beautifulsoup库的信息。终端上输入:

pip show beautifulsoup4

在这里插入图片描述
一种虚拟环境的安装方法(书本上的介绍,了解性内容,pycharm已经可以很好地去实现它了):
在这里插入图片描述

2.运行BeautifulSoup库

下面来运行一个实例:

from urllib.request import urlopen
from bs4 import BeautifulSoup
html=urlopen("http://pythonscraping.com/pages/page1.html")
soup=BeautifulSoup(html.read())#调用 html.read() 获取网页的 HTML 内容
print(soup.div)

由于代码还不完整,有点运行提示,但是不影响想要的输出效果:
在这里插入图片描述
完整网页展示:
在这里插入图片描述

该网页信息有多层结构,但是当我们从对象里提取 div标签的时候,可以直接调用它:

soup.div

类似的,输出同样的效果(等效)还有:
(如果标签所在的其他标签层次结构范围内,也可以这样改写调用,类似于缩小范围提取,比较精确地提取,特别是对于不同结构,相同名称标签的提取,十分有用!)

soup.html.div
soup.body.div

这个例子可以向你展示 BeautifulSoup 库的强大与简单。其实,任何 HTML(或XML)文件的任意节点信息都可以被提取出来,只要目标信息的旁边或附近有标记就行。

3.可靠的网络连接

网络是十分复杂的。网页数据格式不友好,网站服务器宕机,目标数据的标签找不到,都是很麻烦的事情。网络数据采集最痛苦的遭遇之一,由于出现的异常使得爬虫中断或者出现其他问题。所以,我们一开始就要估计可能会出现的异常,从而做出一定的处理,提高爬虫能正确地运行下去的可能性!
下面分析下这一行代码可能出现的问题:

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

这行代码主要可能会发生两种异常:
1.网页在服务器上不存在(或者获取页面的时候出现错误),网页类型错误;
2. 服务器不存在,服务器类型错误;
第一种异常发生时,程序会返回 HTTP 错误。HTTP 错误可能是“404 Page Not Found”“500 Internal Server Error”等。所有类似第一种异常情形,urlopen 函数都会抛出“HTTPError”异常。
我们可以用下面的方式来处理这种异常:

try: 
    html = urlopen("http://www.pythonscraping.com/pages/page1.html") 
except HTTPError as e: 
    print(e) 
    # 返回空值,中断程序(break),或者执行另一个方案
else: 
    # 程序继续。  

如果程序返回HTTPError异常,程序就会显示错误内容或执行except里面的其他语句,不再执行 else 语句后面的代码。
对于第二种情形,如果服务器不存在(就是说链接http://www.pythonscraping.com/ 打不开,或者是 URL 链接输入错误),urlopen 会返回一个 None 对象。这个对象与其他编程语言中的 null 类似。还有一种特殊的异常:URLError,是由于url输入错误引起的异常,他也会发生在第二种情形中,它HTTPError的父类,对于问题的不同,所以要注意使用位置前后。对于第二种情形返回的对象结果,我们 可以增加一个判断语句检测返回的 html 是不是 None:

if html is None: 
    print("URL is not found") 
else: 
    # 程序继续

当然,即使网页已经从服务器成功获取,如果网页上的内容并非完全是我们期望的那样, 仍然可能会出现其他异常。每当你调用 BeautifulSoup 对象里的一个标签时,增加一个检查条件 保证标签确实存在,是很聪明有效的做法。当你想要调用的标签不存在,BeautifulSoup 就会返回 None 对象。不过,如果再调用这个 None 对象下面的子标签,就会发生 AttributeError 错误(异常类型错误,可用try-except语句检查)
下面这行代码(nonExistentTag 是虚拟假设的标签,BeautifulSoup 对象或原本的HTML里面实际不存在的):

print(bsObj.nonExistentTag)

会返回一个 None 对象。处理和检查这个对象是十分必要的。如果你不检查,直接调用这个 None 对象的子标签,就会发生异常:

print(bsObj.nonExistentTag.someTag)

这时就会返回一个异常:

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

为了避免这两种情形的异常,那么可以对这两种情形进行检查:

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, URLError#由于要捕捉urlpen产生的异常,因此要引入这两个函数;
from bs4 import BeautifulSoup
def getTitle(url):#函数:进行网络数据采集,处理可能发生的异常;
    try:
        html = urlopen(url)
    except (HTTPError, URLError) as e:#处理urlopen函数可能产生的两种异常;
        return None
    try:#处理两行代码可能发生的AttributeError异常;
        bsObj = BeautifulSoup(html.read())#如果如果服务器不存在,html 就是一个 None 对象,html.read() 就会抛出 AttributeError;
        title = bsObj.body.h1
    except AttributeError as e:
        return None
    return title
title = getTitle("http://www.pythonscraping.com/pages/page1.html")
if title == None:#判断是否由于触发异常而返回的None,从而执行相关操作;
    print("Title could not be found")
else:
    print(title)

输出效果如下:

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

在写爬虫的时候,考虑并编写好代码的总体格局,让代码既可以捕捉异常又容易阅读,这是很重要的。同时,使用函数(或高级的类)会使代码复用性提高(处理可能发生的所有异常,并进行相关处理),提高我们的编程的效率。

4.拓展:

urllib异常处理中HTTPError和URLError混用的注意事项
URLError和HTTPError基础用法
最后,文中如有不足,敬请批评指正!
后续会有更新,多多关注和点赞!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值