【进阶】Python爬虫采集整个网站
优采云 发布时间: 2020-08-09 10:14前言
在之前的文章中,我们实现了在一个网站上随机地从一个链接到另一个链接,但是,如果我们须要系统地把整个网站按目录分类,或者要搜索网站上的每一个页面,我们该如何办?我们须要采集整个网站,但是那是一种十分花费显存资源的过程,尤其是处理小型网站时,比较合适的工具就是用一个数据库来储存采集的资源,之前也说过。下面来说一下怎样做。
网站地图sitemap
网站地图,又称站点地图,它就是一个页面,上面放置了网站上须要搜索引擎抓取的所有页面的链接(注:不是所有页面,一般来说是所有文章链接,比如我的)。大多数人在网站上找不到自己所须要的信息时,可能会将网站地图作为一种补救举措。搜索引擎蜘蛛特别喜欢网站地图。
对于SEO,网站地图的益处:
1.为搜索引擎蜘蛛提供可以浏览整个网站的链接简单的彰显出网站的整体框架下来给搜索引擎看;
2.为搜索引擎蜘蛛提供一些链接,指向动态页面或则采用其他方式比较无法抵达的页面;
3.作为一种潜在的着陆页面,可以为搜索流量进行优化;
4.如果访问者企图访问网站所在域内并不存在的URL,那么这个访问者都会被转入“无法找到文件”的错误页面,而网站地图可以作为该页面的“准”内容。
数据采集
采集网站数据并不难,但是须要爬虫有足够的深度。我们创建一个爬虫,递归地遍历每位网站,只搜集这些网站页面上的数据。一般的比较费时间的网站采集方法从顶尖页面开始(一般是网站主页),然后搜索页面上的所有链接,形成列表,再去采集到的那些链接页面,继续采集每个页面的链接产生新的列表,重复执行。
很明显,这是一个复杂度下降很快的过程。加入每位页面有10个链接,网站上有5个页面深度,如果采集整个网站,一共得采集的网页数目是105,即100000个页面。
因为网站的内链有很多都是重复的,所以为了防止重复采集,必须链接去重,在Python中,去重最常用的方式就是使用自带的set集合方式。只有“新”链接才能被采集。看一下代码实例:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
pages = set()
def getLinks(pageurl):
globalpages
html= urlopen("" + pageurl)
soup= BeautifulSoup(html)
forlink in soup.findAll("a", href=pile("^(/wiki/)")):
if'href' in link.attrs:
iflink.attrs['href'] not in pages:
#这是新页面
newPage= link.attrs['href']
print(newPage)
pages.add(newPage)
getLinks(newPage)
getLinks("")
原理说明:程序执行时,用函数处理一个空URL,其实就是维基百科的主页,然后遍历首页上每位链接,并检测是否早已在全局变量集合pages上面,如果不在,就复印并添加到pages集合,然后递归处理这个链接。
递归警告:Python默认的递归限制是1000次,因为维基百科的链接浩如烟海,所以这个程序达到递归限制后才会停止。如果你不想使它停止,你可以设置一个递归计数器或则其他方式。
采集整个网站数据
为了有效使用爬虫,在用爬虫的时侯我们须要在页面上做一些事情。我们来创建一个爬虫来搜集页面标题、正文的第一个段落,以及编辑页面的链接(如果有的话)这些信息。
第一步,我们须要先观察网站上的页面,然后制订采集模式,通过F12(一般情况下)审查元素,即可见到页面组成。
观察维基百科页面,包括词条和非词条页面,比如隐私策略之类的页面,可以得出下边的规则:
调整一下之前的代码,我们可以构建一个爬虫和数据采集的组合程序,代码如下:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
pages = set()
def getLinks(pageUrl):
global pages
html = urlopen("" + pageUrl)
soup = BeautifulSoup(html)
try:
print(soup.h1.get_text())
print(soup.find(id="mw-content-text").findAll("p")[0])
print(soup.find(id="ca-edit").find("span").find("a").attrs['href'])
except AttributeError:
print("页面缺乏属性")
for link in soup.findAll("a", href =pile("^(/wiki/)")):
if 'href' in link.attrs:
#这是新页面
newPage = link.attrs['href']
print("------------------\n"+newPage)
pages.add(newPage)
getLinks(newPage)
getLinks("")
这个for循环和原先的采集程序基本上是一样的,因为不能确定每一页上都有所有类型的数据,所以每位复印句子都是根据数据在页面上出现的可能性从高到低排列的。
数据储存到MySQL
前面早已获取了数据,直接复印下来,查看比较麻烦,所以我们就直接存到MySQL上面吧,这里只存链接没有意义,所以我们就储存页面的标题和内容。前面我有两篇文章已经介绍过怎么储存数据到MySQL,数据表是pages,这里直接给出代码:
from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
import datetime
import random
import pymysql
conn = pymysql.connect(host = '127.0.0.1',port = 3306, user = 'root', passwd = '19930319', db = 'wiki', charset ='utf8mb4')
cur = conn.cursor()
cur.execute("USE wiki")
#随机数*敏*感*词*
random.seed(datetime.datetime.now())
#数据储存
def store(title, content):
cur.execute("INSERT INTO pages(title, content)VALUES(\"%s\", \"%s\")", (title, content))
mit()
def getLinks(articleUrl):
html = urlopen("" + articleUrl)
soup = BeautifulSoup(html)
title = soup.find("h1").get_text()
content =soup.find("div",{"id":"mw-content-text"}).find("p").get_text()
store(title, content)
returnsoup.find("div",{"id":"bodyContent"}).findAll("a",href=pile("^(/wiki/)((?!:).)*$"))
#设置第一页
links =getLinks("/wiki/Kevin_Bacon")
try:
while len(links)>0:
newArticle = links[random.randint(0, len(links)-1)].attrs['href']
print (newArticle)
links = getLinks(newArticle)
finally:
cur.close()
conn.close()
小结
今天主要讲一下Python中遍历采集一个网站的链接,方便下边的学习。
希望通过前面的操作能帮助你们。如果你有哪些好的意见,建议,或者有不同的想法,我都希望你留言和我们进行交流、讨论。