1. 概述
京粉(https://union.jd.com/)是京東聯盟下的網站,通過分享其中的商品鏈接可以賺取佣金,類似淘客聯盟。
采集京粉的商品,既可以練習 puppeteer的使用,平時想在京東購物時,也能用得上(采集看看有類似商品的價格和評價)。
2. 主要流程
采集的流程很簡單:
2.1 登錄
登錄本來是很簡單的步驟,只是京粉的登錄有點特殊,它的登錄框是在 iframe 中,所以,加載完網頁后可能登錄框並沒有出現。
需要加載完 iframe 之后才能錄入用戶名/密碼。
登錄模塊的代碼如下:
const username = "YOUR NAME";
const passwd = "YOUR PASSWORD";
// 登錄
const login = async (page) => {
await page.goto("https://union.jd.com/index");
// 等待加載 login 的 iframe
await page.waitForSelector("#indexIframe");
const frame = (await page.frames())[1];
await frame.waitForSelector("#loginname");
// 輸入用戶名和密碼 登錄
await frame.type("#loginname", username, { delay: 100 });
await frame.type("#nloginpwd", passwd, { delay: 100 });
await frame.click("#paipaiLoginSubmit");
};
export default login;
2.2 進入“商品檢索”菜單
登錄成功后,進入首頁,點擊左側的菜單進入“商品檢索”頁面。
注意這里直接使用 page 的 click 方法是無效的,需要使用如下方式:
// 進入商品界面
const productPage = async (page) => {
await page.waitForSelector(".menu-wrapper");
// 直接選擇無法點擊,只能用 page.evaluate 方法來點擊
// 【我要推廣】 菜單
await page.evaluate(
(selector) => document.querySelectorAll(selector)[0].click(),
".el-submenu__title>span"
);
// 【商品推廣】 菜單
await page.evaluate(
(selector) => document.querySelectorAll(selector)[1].click(),
"li.el-menu-item>span"
);
};
2.3 錄入檢索條件並開始檢索
商品推廣頁面支持的檢索條件很多,這里只輸入佣金和價格的范圍來檢索:
// 檢索商品(佣金比例范圍,價格范圍)
const searchProduct = async (page, feeMin, feeMax, priceMin, priceMax) => {
await page.waitForSelector(".imgbox");
await page.waitForSelector("input.el-input__inner");
const inputs = await page.$$("input.el-input__inner");
// IMPORTANT 使用click才能輸入完整,使用 focus,無法輸入完整
await inputs[1].click();
// await inputs[1].focus();
await inputs[1].type(feeMin, { delay: 200 });
await inputs[2].click();
await inputs[2].type(feeMax, { delay: 200 });
await inputs[3].click();
await inputs[3].type(priceMin, { delay: 200 });
await inputs[4].click();
await inputs[4].type(priceMax, { delay: 200 });
// 佣金和價格輸入之后,鼠標必須浮在輸入框上,才會出現確定按鈕去檢索
const divs = await page.$$(".commission");
// div對應的確認按鈕在隱藏的 div中
let popover = await divs[1].evaluate((node) =>
node.getAttribute("aria-describedby")
);
// 通過 hover()函數,讓確定按鈕顯示出來
await inputs[4].hover();
await page.waitForSelector(`#${popover}`, { visible: true });
await page.click(`#${popover}>.el-button--primary`);
};
export default searchProduct;
佣金的范圍(feeMinfeeMax),價格范圍(priceMinpriceMax)是通過參數傳入的。
2.4 保存網頁
保存網頁很簡單,**puppeteer **提供了獲取整個HTML頁面的接口。
// 保存網頁內容到指定路徑
const savePage = async (page, dirname, filename) => {
const html = await page.content();
await saveContent(dirname, filename, html);
};
// 保存解析后的網頁內容到指定路徑
const saveContent = async (dirname, filename, content) => {
if (!mkdirsSync(dirname)) {
console.error("mkdir save page dir ERROR!");
return;
}
fs.writeFileSync(path.join(dirname, filename), content);
};
2.5 進入下一頁
在頁面的最下方有翻頁的按鈕,只要找到下一頁的按鈕即可。
點擊下一頁的函數如下:
// 進入下一頁
const nextPage = async (page) => {
await page.waitForSelector(".el-pagination");
const pageBottons = await page.$$(".el-pagination>button");
// pageBottons[0] -> 上一頁 pageBottons[1] -> 下一頁
await pageBottons[1].click();
await page.waitForNavigation();
};
export default nextPage;
3. 運行效果
4. 總結
以上通過 puppeteer 采集京粉商品數據的實戰中,技術要點主要有:
- 加載 iframe 並自動登錄
- 點擊menu 菜單遷移到商品頁面
- 在文本框中輸入檢索條件
- 自動翻頁
5. 注意事項
爬取數據只是為了研究學習使用,本文中的代碼遵守:
- 如果網站有 robots.txt,遵循其中的約定
- 爬取速度模擬正常訪問的速率,不增加服務器的負擔
- 只獲取完全公開的數據,有可能涉及隱私的數據絕對不碰