python数据采集3-开始采集

python数据采集3-开始采集

遍历单个域名

写一段获取百度百科网站的任何页面并提取页面链接的 Python 代码了

# -*- coding: utf-8 -*-
"""
Created on Fri Jan 26 15:44:26 2018

@author: szm
"""

from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen("https://baike.baidu.com/item/%E7%99%BE%E5%BA%A6/6699")
bsObj = BeautifulSoup(html,"lxml")
for link in bsObj.findAll("a"):
    if 'href' in link.attrs:
        print(link.attrs['href'])

返回结果部分如下:


http://www.baidu.com/
https://www.baidu.com/
http://news.baidu.com/
https://tieba.baidu.com/
https://zhidao.baidu.com/
http://music.baidu.com/
http://image.baidu.com/
http://v.baidu.com/
http://map.baidu.com/
https://wenku.baidu.com/
/
/help
/common/declaration
/
/art
/science
/ziran
/wenhua
/dili
/shenghuo
/shehui
/renwu
/jingji
/tiyu
/lishi
/calendar/
/museum/
/item/史记·2016?fr=navbar
/city/
/operation/worldwar2
/feiyi?fr=dhlfeiyi
/kedou/
/event/ranmeng/
/task/
/mall/
/operation/cooperation#joint
/operation/cooperation#issue
/operation/cooperation#connection
/m#wap
/usercenter
/item/%E7%99%BE%E5%BA%A6%E7%99%BE%E7%A7%91%EF%BC%9A%E5%A4%9A%E4%B9%89%E8%AF%8D
/item/%E4%B9%89%E9%A1%B9
/item/%E7%99%BE%E5%BA%A6?force=1
javascript:;
/item/%E7%99%BE%E5%BA%A6/22343833#viewPageContent
/divideload/%E7%99%BE%E5%BA%A6
/uc/favolemma
javascript:void(0);
javascript:void(0);
javascript:void(0);
javascript:void(0);
javascript:void(0);
javascript:;
javascript:;
/view/10812319.htm
/item/%E7%99%BE%E5%BA%A6
/item/%E6%B5%B7%E6%B7%80%E5%8C%BA
/item/%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6
/item/%E7%BD%91%E7%BB%9C%E4%BF%A1%E6%81%AF%E6%9C%8D%E5%8A%A1
/item/%E4%BA%92%E8%81%94%E7%BD%91
/item/%E5%85%AC%E5%8F%B8
/item/2016%E5%B9%B4
/item/%E6%9D%8E%E5%BD%A6%E5%AE%8F

有一些我们不需要的链接:


/
/help
/common/declaration
/
/art
/science
/ziran
/wenhua
/dili
/shenghuo
/shehui
/renwu
/jingji
/tiyu
/lishi
/calendar/
/museum/
/item/史记·2016?fr=navbar
/city/
/operation/worldwar2
/feiyi?fr=dhlfeiyi
/kedou/
/event/ranmeng/
/task/
/mall/
javascript:void(0);
javascript:void(0);
javascript:void(0);
javascript:void(0);
javascript:void(0);
javascript:;
javascript:;

每个页面都充满了侧边栏、页眉、页脚链接,以及连接到分类页面、对话
页面和其他不包含词条的页面的链接:


javascript:void(0);
javascript:void(0);
javascript:void(0);
javascript:void(0);
javascript:void(0);
javascript:;
javascript:;

如果你仔细观察那些指向词条页面(不是指向其他内容页面)的链接会发现它们都有三个共同点:

  • 它们都在 class 是 para 的 div 标签里
  • URL 链接不包含分号
  • URL 链接都以 /item/ 开头

我们可以利用这些规则稍微调整一下代码来获取词条链接:



# -*- coding: utf-8 -*-
"""
Created on Fri Jan 26 15:44:26 2018

@author: szm
"""

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("https://baike.baidu.com"+articleUrl)
    bsObj = BeautifulSoup(html, "html.parser")
    return bsObj.find("div", {"class":"para"}).findAll("a", href=re.compile("^(/item/)((?!:).)*$"))
links = getLinks("/item/google")
while len(links) > 0:
    newArticle = links[random.randint(0, len(links)-1)].attrs["href"]
    print(newArticle)
    links = getLinks(newArticle)
    


/item/%E8%B0%A2%E5%B0%94%E7%9B%96%C2%B7%E5%B8%83%E6%9E%97
/item/%E6%8B%89%E9%87%8C%C2%B7%E4%BD%A9%E5%A5%87
/item/%E6%96%AF%E5%9D%A6%E7%A6%8F
/item/%E6%97%A7%E9%87%91%E5%B1%B1/29211
/item/%E8%81%94%E5%90%88%E5%9B%BD/135426
/item/%E6%B3%95%E8%AF%AD
/item/%E7%BD%97%E6%9B%BC%E8%AF%AD%E6%97%8F
/item/%E6%84%8F%E5%A4%A7%E5%88%A9%E8%AF%AD


  • 一个函数 getLinks ,可以用维基百科词条 /item/< 词条名称 > 形式的 URL 链接作为参数,
    然后以同样的形式返回一个列表,里面包含所有的词条 URL 链接。
  • 一个主函数,以某个起始词条为参数调用 getLinks ,再从返回的 URL 列表里随机选择
    一个词条链接,再调用 getLinks ,直到我们主动停止,或者在新的页面上没有词条链接
    了,程序才停止运行

采集整个网站

你可能听说过深网(deep Web)、暗网(dark Web)或隐藏网络(hidden Web)之类的
术语,尤其是在最近的媒体中。它们是什么意思呢?

深网是网络的一部分,与浅网(surface Web)对立。浅网是互联网上搜索引擎可以抓
到的那部分网络。据不完全统计,互联网中其实约 90% 的网络都是深网。因为谷歌不
能做像表单提交这类事情,也找不到那些没有直接链接到顶层域名上的网页,或者因
为有 robots.txt 禁止而不能查看网站,所以浅网的数量相对深网还是比较少的。

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

和暗网不同,深网是相对容易采集的。实际上,本书的很多工具都是在教你如何采集
那些 Google 爬虫机器人不能获取的深网信息。

那么,什么时候采集整个网站是有用的,而什么时候采集整个网站又是有害无益的呢?遍
历整个网站的网络数据采集有许多好处。

  • 生成网站地图

  • 几年前,我曾经遇到过一个问题:一个重要的客户想对一个网站的重新设计方案进行效
    果评估,但是不想让我们公司进入他们的网站内容管理系统(CMS),也没有一个公开
    可用的网站地图。我就用爬虫采集了整个网站,收集了所有的链接,再把所有的页面整
    理成他们网站实际的形式。这让我很快找出了网站上以前不曾留意的部分,并准确地计
    算出需要重新设计多少网页,以及可能需要移动多少内容。

  • 收集数据

  • 我的另一个客户为了创建一个专业垂直领域的搜索平台,想收集一些文章(故事、博
    文、新闻等)。虽然这些网站采集并不费劲,但是它们需要爬虫有足够的深度(我们有
    意收集数据的网站不多)。于是我就创建了一个爬虫递归地遍历每个网站,只收集那些
    网站页面上的数据。

一个常用的费时的网站采集方法就是从顶级页面开始(比如主页),然后搜索页面上的所
有链接,形成列表。再去采集这些链接的每一个页面,然后把在每个页面上找到的链接形
成新的列表,重复执行下一轮采集。

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

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

为了全面地展示这个网络数据采集示例是如何工作的,我降低了在前面例子里使用的“只
寻找内链”的标准。不再限制爬虫采集的页面范围,只要遇到页面就查找所有以 /item/ 开
头的链接,也不考虑链接是不是包含分号。(提示:词条链接不包含分号,而文档上传页
面、讨论页面之类的页面 URL 链接都包含分号。)

一开始,用 getLinks 处理一个空 URL,其实是维基百科的主页,因为在函数里空 URL 就
https://baike.baidu.com/ 。然后,遍历首页上每个链接,并检查是否已经在全局变量
集合 pages 里面了(已经采集的页面集合)。如果不在,就打印到屏幕上,并把链接加入
pages 集合,再用 getLinks 递归地处理这个链接。


# -*- coding: utf-8 -*-
"""
Created on Fri Jan 26 15:44:26 2018

@author: szm
"""



from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
import urllib.parse
import string
from urllib.parse import quote

pages = set()
def getLinks(pageUrl):
    global pages
    url="https://baike.baidu.com"+pageUrl
    url=quote(url,safe=string.printable)
    # 这里我们需要对导入的url 进行中文处理 
    html = urlopen(url)
    print("https://baike.baidu.com"+pageUrl)
    bsObj = BeautifulSoup(html, "html.parser")
    
    try:
        print(bsObj.h1.get_text())
        print(bsObj.find("div", {"class":"main-content"}).findAll("div", {"class":"para"}))
        print(bsObj.find("div", {"class":"para"}).findAll("a").attrs['href'])
    except AttributeError:
        print("某个网页抓取失败了")
    
    for link in bsObj.findAll("a", href=re.compile("^(/item/)")):
        if 'href' in link.attrs:
            if link.attrs['href'] not in pages:
               
                newPage = link.attrs['href']
                print("----------------\n"+newPage)
                pages.add(newPage)
                getLinks(newPage)
getLinks("") 

截取部分出去样例



《大中国》简谱
</span>
</div></div>, <div class="para" label-module="para">我们都有一个家</div>, <div class="para" label-module="para">名字叫中国</div>, <div class="para" label-module="para">兄弟姐妹都很多</div>, <div class="para" label-module="para">景色也不错</div>, <div class="para" label-module="para">家里盘着两条龙</div>, <div class="para" label-module="para">是长江与黄河呀</div>, <div class="para" label-module="para">还有珠穆朗玛峰儿</div>, <div class="para" label-module="para">是最高山坡</div>, <div class="para" label-module="para">我们都有一个家</div>, <div class="para" label-module="para">名字叫中国</div>, <div class="para" label-module="para">兄弟姐妹都很多</div>, <div class="para" label-module="para">景色也不错</div>, <div class="para" label-module="para">看那一条长城万里</div>, <div class="para" label-module="para">在云中穿梭呀</div>, <div class="para" label-module="para">看那青藏高原</div>, <div class="para" label-module="para">比那天空还辽阔</div>, <div class="para" label-module="para">我们的大中国呀</div>, <div class="para" label-module="para">好大的一个家</div>, <div class="para" label-module="para">经过那个多少</div>, <div class="para" label-module="para">那个风吹和雨打</div>, <div class="para" label-module="para">我们的大中国呀</div>, <div class="para" label-module="para">好大的一个家</div>, <div class="para" label-module="para">永远那个永远</div>, <div class="para" label-module="para">那个我要伴随她</div>, <div class="para" label-module="para">中国 祝福你</div>, <div class="para" label-module="para">你永远在我心里</div>, <div class="para" label-module="para">中国 祝福你</div>, <div class="para" label-module="para">不用千言和万语</div>, <div class="para" label-module="para">中国 祝福你</div>, <div class="para" label-module="para">你永远在我心里</div>, <div class="para" label-module="para">中国 祝福你</div>, <div class="para" label-module="para">不用千言和万语</div>, <div class="para" label-module="para">高枫的《大中国》是一首校园民谣曲风的歌曲,唱出了祖国河山的多姿多彩,表现了中国人共有的民族自尊与自豪,“一个家”的比喻让人觉得爱国就是那么亲切。这首歌融合了许多地方民歌调子的歌曲,把中国的特点都数了个遍。直至今日,《大中国》唱起来依然是荡气回肠且影响深远。<sup>[7]</sup><a class="sup-anchor" name="ref_[7]_8899232"> </a>
</div>, <div class="para" label-module="para">《大中国》的音乐创作以《<a data-lemmaid="3409383" href="/item/%E4%B8%9C%E6%96%B9%E7%BA%A2/3409383" target="_blank">东方红</a>》、《<a href="/item/%E7%BA%A2%E7%BB%B8%E8%88%9E" target="_blank">红绸舞</a>》以及<a href="/item/%E4%B8%9C%E5%8C%97%E6%B0%91%E6%AD%8C" target="_blank">东北民歌</a><a href="/item/%E6%9C%9D%E9%B2%9C%E6%97%8F%E9%9F%B3%E4%B9%90" target="_blank">朝鲜族音乐</a>作为<a href="/item/%E7%B4%A0%E6%9D%90" target="_blank">素材</a>,在<a href="/item/%E6%9B%B2%E8%B0%83" target="_blank">曲调</a>方面,融合了许多地方民歌调子的歌曲,伴以<a href="/item/%E9%93%BF%E9%94%B5" target="_blank">铿锵</a>喜庆的锣节奏,形成了一种热烈的气氛,使广大听众在听、唱这首歌时,能感到一种强烈的情感和亲切熟悉的音乐与节奏。这首歌曲旋律集中国南北音乐为一体,这样容易被全国各地的人传唱。曲调节奏感强,年轻人不会觉得没有时代感。<sup>[8]</sup><a class="sup-anchor" name="ref_[8]_8899232"> </a>
</div>, <div class="para" label-module="para">歌曲《大中国》是内地原创音乐人高枫创作于1995年的一首流行歌曲。1995年中央电视台《东方时空》音乐电视改版,准备在1995年推出一系列由他们自己制作的新MV ,叫为“95新歌”,一开始他们就选中了《大中国》这首歌。当时组建了一个很大的摄影班子在首都天安门围起了一片摄影地,摄影师、化妆师、导演、灯光、保安人员通力合作,非常热闹。<sup>[5]</sup><a class="sup-anchor" name="ref_[5]_8899232"> </a>
1995年元旦,这首MTV开始在《<a href="/item/%E4%B8%9C%E6%96%B9%E6%97%B6%E7%A9%BA" target="_blank">东方时空</a>》栏目作为一号作品滚动播出,全国各地大街小巷也开始传唱,传遍全国。1996年和1998年,《大中国》更是两次登陆<a href="/item/%E5%A4%AE%E8%A7%86%E6%98%A5%E8%8A%82%E8%81%94%E6%AC%A2%E6%99%9A%E4%BC%9A" target="_blank">央视春节联欢晚会</a><sup>[9-11]</sup><a class="sup-anchor" name="ref_[9-11]_8899232"> </a>
</div>]



通过互联网

建立的网络爬虫也是顺着链接从一个页面跳到另一个页
面,描绘出一张网络地图。但是这一次,它们不再忽略外链,而是跟着外链跳转。我们想
看看爬虫是不是可以记录我们浏览过的每一个页面上的信息,这将是一个新的挑战。相比
我们之前做的单个域名采集,互联网采集要难得多——不同网站的布局迥然不同。这就意
味着我们必须在要寻找的信息以及查找方式上都极具灵活性。

# -*- coding: utf-8 -*-
"""
Created on Fri Jan 26 15:44:26 2018

@author: szm
"""


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

pages = set()
random.seed(datetime.datetime.now())

#Retrieves a list of all Internal links found on a page
def getInternalLinks(bsObj, includeUrl):
    internalLinks = []
    #Finds all links that begin with a "/"
    for link in bsObj.findAll("a", href=re.compile("^(/|.*"+includeUrl+")")):
        if link.attrs['href'] is not None:
            if link.attrs['href'] not in internalLinks:
                internalLinks.append(link.attrs['href'])
    return internalLinks
            
#Retrieves a list of all external links found on a page
def getExternalLinks(bsObj, excludeUrl):
    externalLinks = []
    #Finds all links that start with "http" or "www" that do
    #not contain the current URL
    for link in bsObj.findAll("a", href=re.compile("^(http|www)((?!"+excludeUrl+").)*$")):
        if link.attrs['href'] is not None:
            if link.attrs['href'] not in externalLinks:
                externalLinks.append(link.attrs['href'])
    return externalLinks

def splitAddress(address):
    addressParts = address.replace("http://", "").split("/")
    return addressParts

def getRandomExternalLink(startingPage):
    html = urlopen(startingPage)
    bsObj = BeautifulSoup(html, "html.parser")
    externalLinks = getExternalLinks(bsObj, splitAddress(startingPage)[0])
    if len(externalLinks) == 0:
        internalLinks = getInternalLinks(startingPage)
        return getNextExternalLink(internalLinks[random.randint(0, 
                                  len(internalLinks)-1)])
    else:
        return externalLinks[random.randint(0, len(externalLinks)-1)]
    
def followExternalOnly(startingSite):
    externalLink = getRandomExternalLink("http://www.baidu.com")
    print("Random external link is: "+externalLink)
    followExternalOnly(externalLink)
            
followExternalOnly("http://www.baidu.com")

返回部分结果如下


Random external link is: http://tieba.baidu.com/f?kw=&fr=wwwt
Random external link is: http://news.baidu.com
Random external link is: http://tieba.baidu.com
Random external link is: http://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=
Random external link is: http://map.baidu.com/m?word=&fr=ps01000
Random external link is: http://map.baidu.com/m?word=&fr=ps01000
Random external link is: http://e.baidu.com/?refer=888
Random external link is: http://v.baidu.com
Random external link is: http://www.hao123.com
Random external link is: http://zhidao.baidu.com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=&fr=wwwt
Random external link is: http://music.baidu.com/search?fr=ps&ie=utf-8&key=
Random external link is: http://news.baidu.com
Random external link is: http://zhidao.baidu.com/q?ct=17&pn=0&tn=ikaslist&rn=10&word=&fr=wwwt
Random external link is: http://v.baidu.com
Random external link is: http://music.baidu.com/search?fr=ps&ie=utf-8&key=
Random external link is: http://map.baidu.com/m?word=&fr=ps01000
Random external link is: http://jianyi.baidu.com/
Random external link is: http://map.baidu.com/m?word=&fr=ps01000
Random external link is: http://jianyi.baidu.com/
Random external link is: http://tieba.baidu.com
Random external link is: http://jianyi.baidu.com/
Random external link is: http://tieba.baidu.com/f?kw=&fr=wwwt
Random external link is: http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11000002000001
Random external link is: http://news.baidu.com/ns?cl=2&rn=20&tn=news&word=
Random external link is: http://v.baidu.com
Random external link is: http://v.baidu.com
Random external link is: http://tieba.baidu.com/f?kw=&fr=wwwt
Random external link is: http://map.baidu.com
Random external link is: http://jianyi.baidu.com/
Random external link is: http://music.baidu.com/search?fr=ps&ie=utf-8&key=
Random external link is: http://news.baidu.com/ns

网站首页上并不能保证一直能发现外链。这时为了能够发现外链,就需要用一种类似前面
案例中使用的采集方法,即递归地深入一个网站直到找到一个外链才停止。

posted @ 2018-10-02 22:14  孙中明  阅读(773)  评论(0编辑  收藏  举报