iT邦幫忙

0

關於使用純前端爬蟲,以及ajax巢狀的使用:我來ajax裡ajax!????

  • 分享至 

  • xImage

前情說明

我想問一下,關於爬蟲爬圖片,假設以論壇的表特版為例子,
寫出了爬蟲抓到文章1的裡面圖片網址,接下來url填進去就可以下載任何文章n的圖片。

不過如果當我要一次下載好幾篇的時候,
我又要針對表特版分頁本身做一次爬蟲:找到所有文章的url,
再去文章裡面找到圖片url,就可以抓到圖片了。

疑問部分

所以當我要做這種大量爬好多篇文章的時候,是否就會進入「ajax地獄」:
ajax裡面ajax裡面ajax裡面ajax這樣XDD
之前我寫抓圖是也都這樣寫,運作沒問題,

只是突然在想這種pattern是否是符合常情的XD?
還是說本來就是這樣,不意外σ(´∀`*)

我的另一種做法是分成兩支程式,一支丟出一堆url當作參數,
阿我自己手動再貼進去主程式跑這樣。
但通常還是硬塞ajax裡面ajax 程式就超大一坨這樣(๑• . •๑)

總結

關於這樣子的行為,是否有比較合適的操作方法呢?
或者這無論優劣?都可以討論~
歡迎爬蟲大師前輩們分享一下,自己的經驗跟想法,討論看看囉~~

看更多先前的討論...收起先前的討論...
淺水員 iT邦大師 6 級 ‧ 2023-04-23 18:22:46 檢舉
非同步處理:
Promise
async + await
froce iT邦大師 1 級 ‧ 2023-04-24 08:40:49 檢舉
有個東西叫列表,每個層級先做列表跑一次分析,得到當個層級的所有要處理元素,再對列表中的元素做爬取就好。
基本上就樹狀結構。
會有你所謂的ajax地獄是你規劃沒做好。

然後不要在前端搞爬蟲,這基本上是盜連行為。用別人的內容就算了,你還用別人流量...
問個題外問題
我之前做爬蟲也是大概這樣做
就是用ajax寫好,然後用自己的server掛上proxy去爬別人家的東西
看到force的回覆後想問一下大大
有什麼做法是可以不用別人流量跟盜連呢?
我以為爬蟲就是模擬人的行為拿到資料後回來處理
所以你說的盜連跟用別人流量,我以為的是在取資料回來
如果是大大的話,會怎麼做處理來避免這兩個問題
froce iT邦大師 1 級 ‧ 2023-04-24 13:07:37 檢舉
收到你自己的後端,這樣你只需要浪費別人流量一次就好。流量會從對方的server轉到你的server再給使用者。
前端寫爬蟲,就算你沒踩到CSP問題,流量是從對方server直接到使用者,而且是使用者瀏覽網頁一次,就爬一次,等於你用使用者去抓,而且都是抓同樣的東西。
而你自己的server的流量頂多只有html+js的流量。

另外沒經過對方允許收集對方的資源,自己用還好,還提供人使用就算踩到灰色地帶了。
對,我也是把對方整的頁面整個抓下來在整理的
然後使用者看得到資料,其實是預先處理好的,使用者本身是不能觸發爬蟲的
我的設計的爬蟲是定期作業的,不會讓使用者直接控制爬蟲
我也是自己公司用,就只是做分析,沒有提供給公司以外的使用
感謝大大解我的疑惑
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

0
小哈片刻
iT邦研究生 5 級 ‧ 2023-04-23 21:34:42
最佳解答

你可以準備一個url的陣列,在ajax時就從陣列裏一個一個去抓
每抓完一個url之後,分析裏面的內容,再把新找到想抓的url丟進url陣列
這樣程式看起來就會很清爽

let urlList: string[] = [
    'https://gamelet.online' // 首頁
];
let fetchedUrls: string[] = [];
// 抓一個url的內容並分析
async function fetchURL(url: string) {
    if (fetchedUrls.includes(url)) {
        // 這個網址之前已經抓過了
        return Promise.resolve();
    }
    fetchedUrls.push(url);
    
    let response = await fetch(url);
    let contentType = response.headers.get('content-type');
    if (contentType.startsWith('image/')) {
        ... 儲存圖片...
    } else if (contentType == 'text/html') {
        let content = await response.text();
        ... 儲存內文...
        // 找出頁面中其他的url,加進urlList
        searchOtherUrls(content).forEach(url => urlList.push(url));
    }
}
// 抓全部
async function fetchAll() {
    while (urlList.length) {
        await fetchURL(urlList.shift());
    }
}

// 開始抓
fetchAll();

fetchAll會把網址從urlList裏面一個一個拿出來呼叫fetchURL()下載內容。
而fetchURL會在結束前,把新的url丟進去urlList,讓fetchAll把新找到的url也依序進行處理。

謝謝你具體提供細節 因為是我偶像 就選您為最佳解
希望有空還會繼續拍片 台灣程式的大前輩 也是我童年的製造者
非常感激您解答~
也謝謝另一個前輩的教學 我有學起來這個思路了

0
前端野人
iT邦新手 3 級 ‧ 2023-04-23 21:08:08

大概這思路吧?


const fetchA = async () => {
    try {
        const res = await fetch(url)
        return res
    } catch (error){
        throw error
    }
}

const fetchB= async () => {
    try {
        const res = await fetch(url)
        return res
    } catch (error){
        throw error
    }
}



const combineApi = async () => {
    try {
        const res = await  fetchA()
        const res = await fetchB()
    } catch (error){
        throw error
    }
}

謝謝分享 很好的思維模式 學起來了 感恩

我要發表回答

立即登入回答