获取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

results matching ""

    No results matching ""