使用puppeteer爬取網站,抓出404無效連結

趙陽陽發表於2018-12-20

檢查網頁無效連結

前言

自動化技術可以幫助我們做自動化測試,同樣也可以幫助我們完成別的事情,比如今天我們要做的檢查網站404無效連結。

原理

網站檢查是否有404頁面.png | left | 746x631

實現這樣的功能,大致分為以下步驟: 1.開啟官網首頁,獲取頁面上所有的連結。 2.新增規則對這些連結過濾,把外鏈去掉。 3.遍歷訪問這些連結,開啟開啟其中的每一個連結,檢查是否為404,如果是距離下來。 4.重複執行1,2,3。直到把整個網站所有的連結都遍歷完。

準備

實現

CukeTest中新建一個專案。

image.png | left | 525x254.06091370558377

刪掉features目錄。新建一個demo.js檔案。

image.png | left | 483x296

安裝puppeteer

npm install puppeteer --save
複製程式碼

主要方法講解

pupputeer內建監聽事件,可以很快拿到每個請求的響應結果。

puppeteer可以建立Chromium例項。建立方式如下:

let puppeteer = require('puppeteer');    
browser = await puppeteer.launch({ headless: true });
page = await browser.newPage();
await browser.close();
複製程式碼

puppeteer 提供事件監聽,可以監聽到每個頁面的響應狀態,為每個請求新增響應事件,如果響應狀態碼為404,記錄到檔案中。

page.on('response',(res)=>{
    // console.log("res.url", res.url(), res.status())
    let url = res.url();
    if(res.status()==404){
        linktoFile(url, brokenlinkFile);
    }else{
        if(isvaildUrl(url)){
            linktoFile(url,validUrlFilePath);
        }
        
    }   
})
複製程式碼

puppeteer抓取頁面上所有的連結

await page.goto(url);
//獲取所有的link
const hrefs = await page.evaluate(
    () => Array.from(document.body.querySelectorAll('a[href]'), ({ href }) => href)
);

複製程式碼

將連結記錄到檔案或者從檔案讀取連結的方法

let filetoLinks = function (filepath) {
    if (!fs.existsSync(filepath)) {
        fs.writeFileSync(filepath);
    }
    let data = fs.readFileSync(filepath, 'utf-8')
    let links = data.trim().split('\n');
    return links;
}

let linktoFile = function (link, filepath) {
    let foundLinks = filetoLinks(filepath);
    if (!foundLinks.includes(link)) {
        fs.appendFileSync(filepath, link + '\n');
    }
}

複製程式碼

最終程式碼

let puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');


const host = 'http://www.xxxx.cn/'; // 被測網站
const visitedFile = 'visitedUrl.txt'; //瀏覽過的頁面
const visitedFilePath = path.join(__dirname, visitedFile);
const brokenlinkFile = 'brokenLink.txt'; //404連結
const brokenlinkFilePath = path.join(__dirname, brokenlinkFile);

const validUrlFile = 'validUrlFile.txt'; //可用的連結
const validUrlFilePath = path.join(__dirname,validUrlFile);

let browser;
let page;

function isvaildUrl(url){
    return url.startsWith(host) && !url.includes('/#');
}

async function run() {
    browser = await puppeteer.launch({ headless: true });

    page = await browser.newPage();
    page.on('response',(res)=>{
        // console.log("res.url", res.url(), res.status())
        let url = res.url();
        let currenturl = page.url()
        if(res.status()==404){
            linktoFile(currenturl+"=="+url, brokenlinkFilePath);
        }else{
            if(isvaildUrl(url)){
                linktoFile(url,validUrlFilePath);
            }
            
        }   
    })

    await visitPage(browser,page, host);

    await browser.close();

}

async function visitPage(browser,page, url) {
    // if (!isvaildUrl(url)) return;
    await page.goto(url);
    //獲取所有的link
    const hrefs = await page.evaluate(
        () => Array.from(document.body.querySelectorAll('a[href]'), ({ href }) => href)
    );

    for (const href of hrefs) {
        //資料清洗
        if (isvaildUrl(href) && href !== host) {
            
            //符合條件的link
            // linktoFile(href, visitedFilePath);
            let res = await page.goto(href);
            
            if (res && res.status() == 404) {
                linktoFile(href, brokenlinkFilePath);
            } else {
                let visitedlinks = filetoLinks(visitedFilePath);
                if(!visitedlinks.includes(href)){
                    linktoFile(href, visitedFilePath);
                    await visitPage(browser,page,href);
                    
                }
                
            }

            let links = filetoLinks(visitedFilePath);
            if (!links.includes(href)) {
                await visitPage(browser,page, href);
            }
        }
    }
}

let filetoLinks = function (filepath) {
    if (!fs.existsSync(filepath)) {
        fs.writeFileSync(filepath);
    }
    let data = fs.readFileSync(filepath, 'utf-8')
    let links = data.trim().split('\n');
    return links;
}

let linktoFile = function (link, filepath) {
    let foundLinks = filetoLinks(filepath);
    if (!foundLinks.includes(link)) {
        fs.appendFileSync(filepath, link + '\n');
    }
}

run();
複製程式碼

執行

點選 【執行】按鈕即可執行。 同樣,在CukeTest中也支援命令列執行,執行命令為

cuke --runjs demo.js
複製程式碼

獲取更多相關知識,歡迎關注公眾號

使用puppeteer爬取網站,抓出404無效連結

相關文章