python网络爬虫-采集整个网站

      上一篇文章中,实现了在一个网站上随机地从一个链接跳掉另一个链接。但是,如果需要系统地把整个网站按目录分类,或者要搜索网站上的每一个页面,就得采集整个网站,那是一种非常耗费内存资源的过程,尤其处理大型网站时,最合适的工具就是用一个数据库来储存采集的资源。

 1. 深网和暗网

     你可能听说过深网(deep Web)、暗网(dark Web)或者隐藏网络(hidden Web)之类的术语,尤其在最近的媒体中。它们是什么意思呢?深网是网络的一部分,与浅网(surface Web)对立。浅网是互联网上搜索引擎可以抓到的那部分网络。据不完全统计,互联网中其实约90%网络都是深网。因为谷歌不能做像表单提交这类事情,也找不到那些没有直接链接到顶层域名上的网页,或者因为有robots.txt禁止而不能查看网站,所以浅网的数量相对深网还是比较少的。

     暗网,也被称为Darknet或者dark Internet,完全是另一种“怪兽”。它们也建立在已有的网络基础上,但是使用Tor客户端,带有运行在HTTP之上的新协议,提供了一个信息交换的安全隧道。这类暗网页面也是可以采集的,就像你采集其他网站一样,不过这些内容超出了本章的讨论范围。

     和暗网不同,深网相对容易采集。可以让你采集那些Google爬虫机器人不能获取的深网信息。

2. 遍历整个网站的网络数据采集有许多好处:

  (1)生成网站地图

       使用爬虫采集整个网站,收集所有的链接,再把所有的页面整理成网站实际的形式。

  (2)收集数据

      创建一个专业垂直领域的搜索平台,想收集一些文章(博客,新闻、故事等)。虽然这些网站采集不费劲,但是它们需要爬虫有足够的深度(我们有意猴急数据的网站不多)。于是创建一个爬虫递归地遍历每个网站,只收集那些网站页面上的数据。一个常用的费时的网站采集方法就是从顶级页面开始(比如主页),然后搜索页面上的所有链接,形成列表。再去采集这些链接的每一个页面,然后把每个页面上找到的链接形成新的列表,重复执行下一轮采集。

      很明显,这是一个复杂度增长很快的情形。假如每个页面有10个链接,网站上有5个页面深度(一个中等规模的主流深度),那么如果你要采集整个网站,一共得采集的网页数量就是10^5,即100000个页面。不过,虽然“5个页面深度,每页10个链接”是网站的主流配置,但其实很少的网站真有100000甚至更多的页面,这是因为很大一部分内链都是重复的。

     为了避免一个页面被采集两次,链接去重是非常重要的。在代码运行时,把已发现的所有链接放到一起,并保存在方便查询的列表里(下文示例指Python的集合set类型)。只有新的链接才会被采集,之后再从页面中搜索其他链接。

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

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

getLinks("")
      为了全面地展示这个网络数据采集示例是如何工作的,我去除了“只寻找内链”的标准。不再限制爬虫采集的页面范围,只要遇到页面就查找所有以/wiki/开头的链接,也不考虑链接是不是包含分号。

     一开始,用getLinks处理一个空URL,其实是维基百科的主页,因为在函数里空URL就是https://en.wikipedia.org。然后遍历首页上每一个链接,并检查是否已经在全局变量pages集合中。如果不在,则打印到屏幕,并添加到pages集合中,再用getLinks递归地处理这个链接。这边需要注意一点,python默认的递归限制是1000次,程序到达递归限制后就会自动停止。

3. 收集整个网站数据

     当然,如果只从一个页面跳转到另一个页面,那么网络爬虫是非常无聊的。为了有效地使用它们,在用爬虫的时候我们需要在页面上做些事情。让我们看看如何创建一个爬虫来收集页面标题,正文的第一个段落,以及编辑页面的链接(如果有的话)这些信息。

     和往常一样,决定如何做好这些事情的第一步就是先观察网站上的一些页面,然后拟定一个采集模式。通过观察几个维基百科页面,包括词条页面和非词条页面,比如隐私策略之类的页面,就会得到下面的规则:

     (1)所有的标题(所有页面上,不论是词条页面,编辑历史页面还是其他页面)都是在h1-span标签里,而且页面上只有一个h1标签;

     (2)前面提到过,所有正文文字都在div#bodyContent标签里。但是,如果我们想要进一步获取第一段文字,可能用div#mw-contet-text->p更好(只选择第一段的标签)。这个规则对所有页面都适用,除了文件页面,页面不包含内容文字(content text)的部分内容

      (3)编辑链接只出现在词条页面上,如果有编辑链接,都位于li#ca-edit->span->a里面。

   完整的程序代码如下:

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

pages=set()
def getLinks(pageUrl):
    global pages
    html=urlopen("https://en.wikipedia.org"+pageUrl)
    bsObj=BeautifulSoup(html,"html.parser")
    try:
        print(bsObj.h1.get_text())
        print(bsObj.find(id="mw-content-text").findAll("p")[0])
        print(bsObj.find(id="ca-edit").find("span").find("a").attrs['href'])
    except AttributeError:
        print("页面缺少一些属性,Don't worry")
    for link in bsObj.findAll("a",href=re.compile("^(/wiki/)")):
        if 'href' in link.attrs:
            if link.attrs["href"] not in pages:
                print("---------\n"+newPage)
                newPage=link.attrs["href"]
                pages.add(newPage)
                getLinks(newPage)

getLinks("")
      因为我们不可能确保每一页上都有所有类型的数据,所以每个打印语句都是按照数据在页面上出现的可能性从高到低排列的。也就是说,<h1>标题标签会出现在每一页上,所以我们首先尝试获取它的数据。正文内容会出现在大多数页面上(除了文件页面),因此是第二个获取的数据。“编辑”按钮只出现在标题个正文内容都已经获取的页面上,不是所有页面都有,因此放在最后。


  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值