获取gitbook图书中的所有文章链接
项目大作业中要完成一项任务是,给定一个gitbook图书链接,爬取同一本图书的所有文章链接。本文将通过这一任务,介绍使用python爬取网页信息的一些方法。
获取网页正文
首先,我们需要通过链接获取网页的html源码。这一步可以通过python自带库中的urllib2完成,也可以通过第三方库requests完成。
使用urllib2获取网页源码
from urllib2 import urlopen
url = "https://wp-lai.gitbooks.io/learn-python/content/"
filehandle = urlopen(url)
html = filehandle.read()
print html
使用requests获取网页源码
import requests
url = "https://wp-lai.gitbooks.io/learn-python/content/"
r = requests.get(url)
print r.text
添加http代理
有些网站在墙外,这时可以使用http代理。http代理在urllib和requests中的设置方法类似。
在urllib中:
from urllib import urlopen
url = "https://wp-lai.gitbooks.io/learn-python/content/"
proxies = {'http': 'http://www.someproxy.com:port'} #设置http代理
filehandle = urlopen(url, proxies=proxies) # 在用urlopen时使用proxies参数
html = filehandle.read()
print html
在requests中:
import requests
url = "https://wp-lai.gitbooks.io/learn-python/content/"
proxies = {'http': 'http://www.someproxy.com:port'} #设置http代理
r = requests.get(url, proxies=proxies) # 使用proxies参数
print r.text
检查链接有效性
有时需要考虑链接失效的情况。
当使用urlopen链接无效链接时,会抛出HTTPError错误。
from urllib2 import urlopen, HTTPError # 记得导入HTTPError
url = "https://wp-lai.gitbooks.io/learn-python/content/make_some_nonsense.html"
try:
filehandle = urlopen(url)
except HTTPError as e:
print e #根据情况处理抛出的错误
else:
print filehandle.read()
而在requests中,可以通过检查ok属性来知道链接是否有效。
import requests
url = "https://wp-lai.gitbooks.io/learn-python/content/make_some_nonsense.html"
r = requests.get(url)
assert r.ok # 如果r.ok为false,则抛出AssertionError, 退出程序
print r.text
获取页面中特定元素
获取到页面源码之后,我们需要解析html代码,从中获得想要的信息。
在本文任务中,我们需要爬取gitbook图书目录中所有章节对应的链接。
beautifulsoup + css选择
...
<li class="chapter " data-level="1" data-path="0MOOC/index.html">
<a href="./0MOOC/index.html">
...
仔细观察源码,可以发现想要的信息是a
标签中href属性的内容,而且是class为'chapter'的li
标签下的a
标签。
总结出元素出现的规律之后,就可以使用第三方库beautifulsoup来提取想要的信息。
- 通过findAll('li')函数可以找到所有
li
标签节点 - 如果想要限定class元素的话,可以这样写
- findAll('li', {'class':'chapter'})
- 或findAll('li', class_='chapter')
- 获取节点tag下
a
标签的href属性值,可以这样写:- tag.a.attrs['href']
- 或者tag.a['href']
综合为一下代码:
# 假设html源码已经赋值到html这个变量中了
from bs4 import BeautifulSoup
soup = BeautifulSoup(html)
tags = soup.findAll('li', {'class':'chapter'})
links = []
for tag in tags:
links.append(tag.a.attrs['href'])
print links
如果想让代码更简洁,可以使用列表解析式
from bs4 import BeautifulSoup
soup = BeautifulSoup(html)
links = [tag.a['href']
for tag in soup.findAll('li', {'class':'chapter'})]
print links
使用正则表达式
正则表达式可以用来匹配字符串中的线性模式。
观察html源码可以发现想要提取的链接存在如下规律:
- 以一个或两个
.
开头 -> `[.]{1,2}`` - 紧跟
/
->\/
- 中间由字母数字和
/
组成 ->[A-Za-z0-9\/]+
- 以
.html
结尾
上述规律翻译成正则表达式就是 [\.]{1,2}\/[A-Za-z0-9\/]+\.html
接着就可以用python中的正则表达式库re进行信息提取
import re
pattern = "[\.]{1,2}\/[A-Za-z0-9\/]+\.html"
links = re.findall(pattern, html)
print links
补足路径
需要注意的是,在这个任务里,上述方法抓取到的是相对路径,如./0MOOC/index.html
,而希望获得的是完成的链接地址,那么需要额外写一个函数将相对路径转成绝对地址,可以用urlparse模块中的urljoin完成这个功能。
def complete_link(current_url, url):
from urlparse import urljoin
dest_url = urljoin(current_url, url)
return dest_url