之前强行采集了非常简单的HTML页面当中 显而易见的一些数据,对于实际情况而言存在的意义只是练习亦或者是认识BeautifulSoup的强大。这次稍加难度,就尝试一些不一样的东西:
之前看到 一个 非常有趣的现象:在我刚刚建站的时候关于 百度KelovpString这个词是 没有任何有关本站的信息,而一周左右之后百度蜘蛛似乎发现的这个站点的存在,很明显百度快照的检索工具也是一直在不停的干一件事情:遍历。在这之前似乎要获取我网站的内容得需要URL,通过主页面所得到的URL去检索这个页面当中所有的url挨个访问。很是暴力但这个时候会出现一个问题:我首页的图标和 首页所对应的URL都是同一个,在此时进行采集明显是 会重复的,这样无疑会加重服务器的负载,所以得另想办法。
百度百科
选择百度百科作为采集目标吧=-=事前查看了一下大概特点:
百度的网页是py的吧。。怎么还有wiki--先不说这个
在检索词条时有几个共同点:
1、所有词条之前都会有item,格式是https://baike.baidu.com/item+词条
2、URL不包含分号
3、词条的内同都写在一个class 为content的div标签当中
所以可以把该页面的词条链接先扒下来:
from urllib import urlopen from bs4 import BeautifulSoup import re html = urlopen("https://baike.baidu.com/item/Avicii") bsObj = BeautifulSoup(html,"html.parser") for link in bsObj.find("div", {"class":"content"}).findAll("a", href=re.compile("^(/item/)((?!:).)*$")): if 'href' in link.attrs: print(link.attrs['href'])
这样就一下子得到一些链接:
这些链接都是本页面的所有链接,但 前面就说了,我们要遍历,遍历就是一直往里钻啊,直到底部(滑稽)
这样可以利用python当中的getlinks:
from urllib 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":"content"}).findAll("a", href=re.compile("^(/item/)((?!:).)*$")) links = getLinks("/item/Avicii") while len(links) > 0: newArticle = links[random.randint(0, len(links)-1)].attrs["href"] print(newArticle) links = getLinks(newArticle)
这次算的上真正意义的遍历了,但是在上面用了随机路径:用随机函数把当前时间作为种子,让每次词条的选择都是一个全新的随机路径(所以肯定是单纯的跳来跳去,好比从树的根结点一直走到深度最大的叶子结点,而且是该路径的上的最大深度)。上面的程序也就是部分情况能用,在没有异常处理的情况下上面的代码还是很脆弱的 。
依旧是百度百科
如果像是题头那样,采集一个网站,把采集下来的东西 分类存放,或者说把每个页面的某个特有性的资源保存(比如图片),我是很难做到测试了。但可以做些简单的采集
假如我从根目录(百科的https://baike.baidu.com)开始搞事,然后搜索页面上所有的链接,形成列表,再去采集这些链接的每一个页面,然后依次这样执行。但是这样就会出现题头所说的问题:重复的URL。这个时候就凸现出set()集合的强大之处了。让采集到的链接存放至set集合当中,重复的内容就被去掉了,只有新的链接才会被继续搜索:
from urllib import urlopen from bs4 import BeautifulSoup import re pages = set() def getLinks(pageUrl): global pages html = urlopen("https://baike.baidu.com" + pageUrl) bsObj = BeautifulSoup(html, "html.parser") 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(newPage) pages.add(newPage) getLinks(newPage) getLinks("")
一开始,用 getLinks 处理一个空 URL,因为在函数里空 URL 就是 https://baike.baidu.com。然后,遍历首页上每个链接,并检查是否已经在全局变量集合 pages 里面了(已经采集的页面集合)。如果不在,就打印到屏幕上,并把链接加入pages 集合,再用 getLinks 递归地处理这个链接。
关于递归:python里默认的递归次数是1000次,所以对于百科这样一个庞大的网站而言1000根本不足以探求到底。但是上面的代码只是单纯的从一个链接跳转到另外一个链接,这样可以结合之前的检索方法来实现一些数据的提取