web scraping with python

之前就有对网络爬虫很感兴趣,觉得这是一件比较有意思的事情,奈何前段时间有接触过,学到后面的时候有点吃力,总结了一下原因之后觉得最直接的原因就是在前端方面自己接触的还是太少了,现在在准备论文之余。。。(为何总对论文的内容不感兴趣呢-_-!)再来重新看一遍爬虫吧。。哈哈,突然觉得保持一整天学习的热情的秘诀就是:

***把每一天的早晨的时间都用在自己感兴趣的事情上。***

好了,进入正题,直接来看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from urllib.request import urlopen
from urllib.error import HTTPError,URLError
from bs4 import BeautifulSoup
def getTitle(url):
try :
html=urlopen(url)
except (HTTPError,URLError) as e:
return None
try:
bsObj=BeautifulSoup(html.read())
title=bsObj.body.h1
except AttributeError as e:
return None
return title

title=getTitle("http://aisleep.xyz")
if title ==None:
print("Title could not be found")
else:
print(title)

首先是引入几个需要用到的库,request中的urlopenbeautifulsoup,是爬虫经常需要用到的库(这里代码中的BeautifulSoupBeautifulSoup库中的BeautifulSoup对象,不是指的BeautifulSoup库),前者是自带的,能够直接获取网页中的html代码,而后者是第三方库,需要自己安装,他是用来转换我们得到的html代码的结构,使其能够只要目标信息的旁边或附近有标记(这里说的标记是HTML中的标记)我们就能够提取出来。HTTPErrorURLError则是对异常的处理所需要的。

我们这里首先定义了一个名为getTitle的函数。我们在进行这个语句的时候:html=urlopen("http://aisleep.xyz")这行代码可能会发生两种异常:1、网页不在服务器上;2、服务器不存在。发生第一种异常,程序会抛出HTTpError异常,发生第二种异常,程序会返回一个None对象。所以getTitle函数中的第一个异常处理针对于HTTPError,还增加了一个防止url地址输入错误引起的URLError

然后,我们在使用BeautifulSoup去提取我们所需要的信息时也会出错:如果我们想要调用的标签不存在,BeautifulSoup会返回一个None对象;如果再去调用这个None对象下面的子标签,还会发生AttributeError错误。

所以第二个异常处理针对于:1、因为服务器不存在而返回一个None值,后再调用这个None值(通过html.read()调用)引起的AttributeError异常。2、因为我们使用BeautifulSoup调用一个不存在的标签的时候返回了一个None值,后再调用这个None值下面的子标签而造成的AttributeError异常。

针对于爬虫中比较常见的异常处理,这样一来就会很简单的使自己的代码更稳定一点。


上面的是采集一个页面中需要的信息,下面再看一个代码,实现随机的从一个页面跳转到另一个页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from urllib.request import urlopen
from bs4 import BeautifulSoup
import datetime
import random
import re

random.seed(datetime.datetime.now())

def getLinks(articleUrl):
html=urlopen("http://en.wikipedia.org"+articleUrl)
bsObj=BeautifulSoup(html)
return bsObj.find("div",{"id":"bodyContent"}).findAll("a",href=re.compile("^(/wiki/)((?!:).)*$"))

links=getLinks("/wiki/Kevin_Bacon")

while len(links)>0:
newArticle=links[random.randint(0,len(links)-1)].attrs["href"]
print(newArticle)
links=getLinks(newArticle)

首先这里导入了一些需要的库,datetimerandom分别是为了生成一个随机数生成器。第7行中就是通过当前时间为值实现了一个随机数生成器。接着定义了一个函数getLitle我们传入的是以http://en.wikipedia.org为开头的url然后传入Beautifulsoup,最后返回在当前网页(用的是find)中的在div标签下的idbodyContent的,且不包含:的以/wiki/开头的所有url链接(返回的是一个列表,这里用了正则表达式来匹配所要满足条件的链接)。

第14行写到以Kevin_Bacon为开始页面,调用getLinks函数。16行往下是指在返回的列表不为空的情况下,以随机数生成器生成的随机数作为列表的序号,去访问另一个链接,跳转到另一个页面,打印这个链接,最后又将此链接传给getLitle函数。


接下面再看一个代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

pages=set()
def getLinks(pageUrl):
global pages
html = urlopen("http://wikipedia.org"+pageUrl)
bsObj=BeautifulSoup(html)
for link in bsObj.findAll("a",href=re.compile("^(/wiki/)")):
if 'href' in link.attrs:
if link.attrs['href'] not in pages:
newPage=link.attrs['href']
print(newPage)
pages.add(newPage)
getLinks(newPage)
getLinks("")

由于链接之间很多都是重复的,所以自然就会有需要“链接去重”的功能。
首先定义了一个set集合类型的变量pages,接着我们看getLinks函数,第7行是定义全局变量pages,然后找到以/wiki/开头的链接。第12行是判断这个链接是否在pages中,如果不在就说明是新链接,打印且将他增加到pages中,最后将这个newPage又传入getLinks函数,递归处理。