通过404链接验证爬虫来理解深度优先和宽度优先遍历

需求

事情是这样的,最近需要把一个域名下面的所有404的页面链接给抓出来,因为这个域名下面的链接实在太多了,人工的方法肯定不行,网上也没有找到什么现成的工具,但是我是谁啊,脚本小能手啊,那就自己用python撸一个咯

深度优先遍历

一开始是这么想的,拿到根路径之后先把所有的子路径拿出来,分别用urllib去验证这些路径,如果验证不通过则记录下来,否则则用该子路径作为根路径去遍历他的子路径,废话不多说直接上代码

#  递归 深度优先遍历
import urllib.request
from urllib.request import URLError
import http.cookiejar
from selenium import webdriver  
passlist = {
    
    }
path = {
    
    }
def getCurrent(urlRoot):
    try:
        if urlRoot in path:
            return
        driver.get(urlRoot)   # 要测试的页面 
        path[urlRoot] = 1
        # try:
        #     devloplist = driver.find_elements_by_id("in-the-process-of-development")
        #     if(len(devloplist)!=0):
        #         devlopPath = open("devlopPath.txt","a+")
        #         devlopPath.write(urlRoot+"\n")
        #         devlopPath.close()            
        # except:
        #     print("not devlopment")
        finally:
            #urlRoot = urlRoot.split('#')
            urls = driver.find_elements_by_xpath("//a") # 匹配出所有a元素里的链接
            us = []
            for url in urls:
                us.append(url.get_attribute('href'))
            for u in us:
                if u == 'None':   # 很多的a元素没有链接,所有是None
                    continue
                if u.find("https://dynamsoft.github.io/barcode-sdk-docs-dev")==-1:#控制域名防止跳转到其他站点
                    continue
                if urlRoot+","+u in passlist:
                    continue
                try:
                    response=urllib.request.urlopen(u)   # 可以通过urllib测试url地址是否能打开
                except:
                    passlist[urlRoot+","+u]=1
                    errorPath = open("errorPath.txt","a+")  #记录不成功的路径
                    errorPath.write(urlRoot+","+u+"\n")     #父路径:子路径的格式保存
                    errorPath.close()
                    print('Error url:   '+urlRoot+","+ u)   # 把测试不通过的url显示出来
                    continue
                else:
                    passlist[urlRoot+","+u]=1
                    print('Success url:   ' + u)   # 测试通过的url展示出来
                    getCurrent(u)
    except:
        return



option=webdriver.ChromeOptions()
#option.add_argument("headless")
driver = webdriver.Chrome('C:\\Program Files (x86)\\Google\\Chrome\\Application\\chromedriver.exe')
getCurrent("https://dynamsoft.github.io/barcode-sdk-docs-dev")
driver.close()       

理想是美好的,但是现实总是不如人意,我挂着爬虫第二天起来一看,卧槽,崩溃了!

可以我明明在最外层加上try catch了啊,所以是不会有异常导致的崩溃的,于是我看了一眼errorPath.txt这个文件,效果还是有的,找到了很多的404路径

可以看出这个域名下面的链接非常的多,于是我把option.add_argument(“headless”)这行代码注释掉了,模拟了一下这个爬虫爬的路径。

害,怪不得呢,这个爬虫逻辑是没什么问题,问题就出在他是个递归,递归是通过函数调用栈来模拟栈的,每次递归都会压栈,资源是有限的,压着压着就炸了呗
这里有两种解决办法

  • 方法一
    通过python的栈来存地址路径,简单点来说就是改递归为循环通过stack的数据结构来实现
  • 方法二
    采取宽度优先遍历,通过队列来实现遍历,每次拿出队头的路径,然后将验证通过的路径加入队列中,把验证不通过的路径记录下来

深度优先遍历

这里我用了第二种方法,不说废话,上代码

#宽度优先遍历

import urllib.request
from urllib.request import URLError
import http.cookiejar
from selenium import webdriver
import queue
option=webdriver.ChromeOptions()
option.add_argument("headless")
faillist = {
    
    }
passlist = {
    
    }
q = queue.Queue()
q.put("https://dynamsoft.github.io/barcode-sdk-docs-dev")
driver = webdriver.Chrome('C:\\Program Files (x86)\\Google\\Chrome\\Application\\chromedriver.exe',chrome_options = option)
while(not q.empty()):
    try:
        print(q.qsize())
        url = q.get()    
        driver.get(url)
        urls = driver.find_elements_by_xpath("//a") # 匹配出所有a元素里的链接
        us = []
        for data in urls:
            us.append(data.get_attribute('href'))
        for i in range(len(us)):
            u = us[i]
            if u.find("https://dynamsoft.github.io/barcode-sdk-docs-dev")==-1:
                continue
            if u in passlist:
                #print(u+"已经遍历过")
                if passlist[u]==0:# 失败
                    errorPath = open("errorPath.txt","a+")
                    errorPath.write(url+","+u+",from fail dict\n")
                    errorPath.close()
                else:# 通过的
                    continue
            else:
                #print(u+"没有遍历过")
                try:
                    response=urllib.request.urlopen(u)# 可以通过urllib测试url地址是否能打开
                except Exception as e:
                    print(e)
                    errorPath = open("errorPath.txt","a+")
                    errorPath.write(url+","+u+","+str(e)+"\n")
                    errorPath.close()
                    #print('Error url:   '+url+","+ u)   # 把测试不通过的url显示出来
                    passlist[u]=0
                    continue
                else:
                    #print('Success url:   ' + u)   # 测试通过的url展示出来
                    passlist[u]=1
                    q.put(u)
    except:
        continue

反正就是把地址记录下来,把函数调用栈的资源改成内存资源,这样就不会崩溃啦,q.qsize()输出为1的时候就是遍历结束的时候!

讲道理,我觉得有点深度优先和宽度优先遍历的意思在里头了。。。

哦对了,还有一点,urllib测试不通过的链接不一定全是404链接,还有一部分是因为你一直去访问这个站点,会被人家当成是在攻击人家,这种在计算机安全里面好像叫做拒绝服务攻击,英文叫DoS。

总之不是所有爬下来的链接都是404你可以在except Exception as e:里面继续改一下如果 e是<urlopen error [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond>的话就passlist[u]=1咯

anyway, 我实现写的烂了点,但是我懒得改了,很可怕了~如果你们需要404链接验证爬虫就将就着用吧。。。

猜你喜欢

转载自blog.csdn.net/weixin_38616018/article/details/106837652