十年網(wǎng)站開發(fā)經(jīng)驗 + 多家企業(yè)客戶 + 靠譜的建站團隊
量身定制 + 運營維護+專業(yè)推廣+無憂售后,網(wǎng)站問題一站解決
在進行廣度優(yōu)先和深度優(yōu)先查找前,先定義一個數(shù)據(jù)結(jié)構(gòu)。這里我用二叉樹,每個節(jié)點的定義如下:

創(chuàng)新互聯(lián)建站主要從事網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)東川,十年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575
class Node(object):
def __init__(self, item, left=None, right=None):
self.item = item
self.left = left
self.right = right
def __str__(self):
return '%s' % self.item
下面的代碼從命令行接收參數(shù),遞歸的生成一個指定深度的滿二叉樹。
counter = 0
def create_tree(deep):
if deep < 0:
return None
global counter
counter += 1
root = Node(counter, deep)
root.left = create_tree(deep-1)
root.right = create_tree(deep-1)
return root
if __name__ == '__main__':
import sys
s = sys.argv[1]
n = s.isdigit() and int(s) # 不是數(shù)字就是False,F(xiàn)alse就是0
r = create_tree(n)
print(r, r.left, r.right)示例盡量簡單,這里就用了全局變量。
深度優(yōu)先可以用遞歸的方法來實現(xiàn)。上面創(chuàng)建的時候也是使用遞歸來創(chuàng)建的,所以創(chuàng)建節(jié)點的順序也是深度優(yōu)先。
所以這里再寫一個遞歸函數(shù),遍歷每個節(jié)點并且打印出來:
def print_tree(root):
if root is None:
return
print(root)
print_tree(root.left)
print_tree(root.right)
if __name__ == '__main__':
import sys
s = sys.argv[1]
n = s.isdigit() and int(s) # 不是數(shù)字就是False,F(xiàn)alse就是0
r = create_tree(n)
print_tree(r)這里節(jié)點是按創(chuàng)建的順序輸出的,因為創(chuàng)建的時候也是這樣的一個遞歸的邏輯。
前序遍歷
這個是二叉樹的概念,上面的例子就是前序遍歷。
前序遍歷:根結(jié)點 ---> 左子樹 ---> 右子樹
有前序遍歷,就還有中序和后序
中序遍歷
中序遍歷:左子樹---> 根結(jié)點 ---> 右子樹
def print_tree(root):
if root is None:
return
print_tree(root.left)
print(root) # 根節(jié)點這句移到中間
print_tree(root.right)后序遍歷
后序遍歷:左子樹 ---> 右子樹 ---> 根結(jié)點
def print_tree(root):
if root is None:
return
print_tree(root.left)
print_tree(root.right)
print(root)
實現(xiàn)廣度優(yōu)先,只需要操作列表就可以了。遍歷列表里的每一個元素,輸出該元素并把子元素添加到一個新的列表里,給下一次遍歷來操作:
def print_tree(l):
work = [l]
while len(work) > 0:
items, work = work, [] # 復(fù)制一份用于遍歷,并把自己清空,接收下一次要遍歷的元素
for i in items:
if i is None:
continue
print(i)
work.append(i.left)
work.append(i.right)層次遍歷
相對于二叉樹的前序遍歷,這個遍歷的方法叫層次遍歷。
網(wǎng)頁爬蟲的核心是解決圖的遍歷。對于網(wǎng)絡(luò)爬蟲,一般使用的就是廣度優(yōu)先的遍歷。
下面的示例,從命令行接收url,把這個url下的所有鏈接打印出來。然后繼續(xù)對這些鏈接發(fā)起請求,打印鏈接,一直循環(huán)下去:
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
def extract(url):
"""向給定的url發(fā)起GET請求,
解析HTML,返回其中存在的鏈接
"""
try:
response = requests.get(url, timeout=0.1) # 注意這里設(shè)置了超時時間
except Exception:
return False
if not response.ok:
return False
global deep
print("DEEP:", deep, url)
soup = BeautifulSoup(response.text, features='html.parser')
targets = soup.find_all('a')
links = []
for i in targets:
links.append(urljoin(url, i.attrs.get('href')))
return links
def breadth_first(urls):
seen = {} # 記錄去重的字典
global deep
while len(urls) > 0:
deep += 1
items, urls = urls, []
for i in items:
if not seen.get(i):
seen.setdefault(i, True)
links = extract(i)
if links:
urls.extend(links) # 向列表尾部添加多個元素
deep = 0
if __name__ == '__main__':
import sys
breadth_first(sys.argv[1:]) # http://lab.scrapyd.cn/ 這個站點用來做實驗不錯部分執(zhí)行結(jié)果:
$ python 5crawl.py http://lab.scrapyd.cn/
DEEP: 1 http://lab.scrapyd.cn/
DEEP: 2 http://lab.scrapyd.cn/archives/57.html
DEEP: 2 http://lab.scrapyd.cn/tag/%E8%89%BA%E6%9C%AF/
DEEP: 2 http://lab.scrapyd.cn/tag/%E5%90%8D%E7%94%BB/
DEEP: 2 http://lab.scrapyd.cn/archives/55.html
DEEP: 2 http://lab.scrapyd.cn/archives/29.html
DEEP: 2 http://lab.scrapyd.cn/tag/%E6%9C%A8%E5%BF%83/
DEEP: 2 http://lab.scrapyd.cn/archives/28.html
DEEP: 2 http://lab.scrapyd.cn/tag/%E6%B3%B0%E6%88%88%E5%B0%94/
DEEP: 2 http://lab.scrapyd.cn/tag/%E7%94%9F%E6%B4%BB/
DEEP: 2 http://lab.scrapyd.cn/archives/27.html
DEEP: 2 http://lab.scrapyd.cn/tag/%E6%99%BA%E6%85%A7/
DEEP: 2 http://lab.scrapyd.cn/page/1/
DEEP: 2 http://lab.scrapyd.cn/page/2/
DEEP: 2 http://lab.scrapyd.cn/page/3/
DEEP: 2 http://lab.scrapyd.cn/page/4/
DEEP: 2 http://lab.scrapyd.cn/page/6/
DEEP: 2 http://lab.scrapyd.cn/tag/%E4%BA%BA%E7%94%9F/
DEEP: 2 http://lab.scrapyd.cn/tag/%E5%8A%B1%E5%BF%97/
DEEP: 2 http://lab.scrapyd.cn/tag/%E7%88%B1%E6%83%85/
DEEP: 2 http://lab.scrapyd.cn/tag/%E7%8E%8B%E5%B0%94%E5%BE%B7/
DEEP: 2 http://lab.scrapyd.cn/tag/%E7%BB%9D%E4%B8%96%E5%A5%BD%E8%AF%8D/
DEEP: 2 http://lab.scrapyd.cn/tag/%E8%AF%8D/
DEEP: 2 http://lab.scrapyd.cn
DEEP: 2 http://www.scrapyd.cn
DEEP: 3 http://lab.scrapyd.cn/archives/26.html
DEEP: 3 http://lab.scrapyd.cn/archives/25.html
DEEP: 3 http://lab.scrapyd.cn/archives/24.html
DEEP: 3 http://lab.scrapyd.cn/archives/23.html
DEEP: 3 http://lab.scrapyd.cn/archives/22.html
DEEP: 3 http://lab.scrapyd.cn/page/5/理論上這個程序會把所有可達(dá)的網(wǎng)頁都訪問到,或者內(nèi)存耗盡。
現(xiàn)在的內(nèi)存也沒那么塊能耗盡。然后互聯(lián)網(wǎng)也是無限延伸的,基本上就是沒完沒了了。
不過實際上,遇到某個下載的鏈接就會卡住了。這個不是這篇的重點,就不深究了。