برنامه نویسی

Web Scraping With Puppeteer برای Total Noobs: قسمت 3

سلام و به سومین و آخرین پست این مجموعه خوش آمدید. اگر قبلی را از دست دادید، لطفاً قبل از ادامه، آنها را به سرعت بخوانید. در این پست به شما نشان خواهم داد که چگونه یک GitHub Action را تنظیم کنم تا به طور خودکار برخی از داده های آب و هوا را بر اساس یک برنامه حذف کنم.

قبل از شروع باید به شما بگویم که من منبع داده های آب و هوا را به دلیل برخی عوارض با weather.com تغییر دادم. من مطمئن هستم که می توانم از مشکلاتی که داشتم عبور کنم، اما برای اینکه بدون فشار اضافی به جلو بروم، منبع را به منبعی تغییر دادم که معتقدم باعث ناراحتی شما نخواهد شد.

توجه: این پست فرض می کند که شما با ایجاد و به روز رسانی یک مخزن GitHub راحت هستید

رسیدن

در پست قبلی با شما به اشتراک گذاشتم scrape تابعی که برای خراش خروجی weather.com و console.log استفاده کردیم. من ادامه می دهم و به روز شده را جایگذاری می کنم scrape تابع، با منبع جدید زیر:

async function scrape() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  await page.goto(
    "https://www.weathertab.com/en/d/united-states/texas/austin/"
  );

  const weatherData = await page.evaluate(() =>
    Array.from(document.querySelectorAll("tr.fct_day"), (e) => ({
      dayOfMonth: e.querySelector("td > div.text-left > .fct-day-of-month")
        .innerText,
      dayName: e.querySelector("td > div.text-left > .fct-day-of-week")
        .innerText,
      weatherIcon: e.querySelector("td.text-center > .fct_daily_icon")
        .classList[1],
      weatherIconPercent: e
        .querySelector("td.text-center")
        .getElementsByTagName("div")[1].innerText,
      highTempRange: e.querySelector(
        "td.text-center > .F > div > .label-danger"
      ).innerText,
      lowTempRange: e
        .querySelector("td.text-center > .F")
        .getElementsByTagName("div")[1].innerText,
    }))
  );

  await browser.close();
  return weatherData;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همانطور که می بینید، منبع در حال حاضر است https://www.weathertab.com/en/d/united-states/texas/austin/، البته می توانید این را به هر شهری که دوست دارید تغییر دهید. منطق عملاً یکسان است (مثل اینکه در حال ایجاد آرایه ای از داده ها هستیم)، با این حال، از آنجایی که ما منابع را تغییر دادیم، البته باید عناصر موجود در صفحه را هدف قرار دهیم، که بدون شک با صفحه weather.com متفاوت هستند. . به جای پیش بینی 10 روزه، اکنون کل پیش بینی ماه جاری را دریافت می کنیم.

داده ها بدون برخی زمینه ها کمی عجیب هستند. با این حال، من مطمئن هستم که می‌توانید نوعی نقشه یا شی ایجاد کنید که داده‌ها، مانند نماد آب و هوا و درصد نماد آب و هوا را به چیزی معنادار تبدیل کند.

به هر حال، با نمایش ادامه دهید.

آماده شدن برای نوشتن داده ها

برای اینکه بتوانیم به هدف نهایی از نوشتن این داده های خراشیده شده برسیم .json فایل در یک مخزن GitHub، ما باید چند نکته نهایی را به آن اضافه کنیم scraper.js فایل. مسلماً، من در مورد تعامل با سیستم فایل با استفاده از node.js (یا هر زبان دیگری) متخصص نیستم. با این حال، من می توانم راه خود را با فناگیر کنم. من آنچه را که دارم با شما به اشتراک می گذارم، و اگر شما در این موضوع از من آگاه تر هستید، لطفاً جای خالی را پر کنید.

ما می خواهیم داده های خراشیده شده خود را در فایلی در مخزن خود بنویسیم که نام آن را می گذاریم weatherdata.json.

برای انجام این کار، ما این خط را در پایان کار خود خواهیم داشت scraper.js فایل:

// execute and persist data
scrape().then((data) => {
  // persist data
  fs.writeFileSync(path.resolve(pathToData), JSON.stringify(data, null, 2));
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

را writeFileSync متد بخشی از ماژول سیستم فایل node.js است. در اینجا می توانید اطلاعات بیشتری در مورد این روش کسب کنید. اساساً کاری که ما با آن انجام می دهیم عبور در مسیر پرونده خود است weatherdata.json به عنوان پارامتر اول، و داده های خراشیده شده ما به عنوان پارامتر دوم. این writeFileSync متد اگر فایلی وجود نداشته باشد، آن را ایجاد می‌کند، یا در صورت وجود، فایل را با داده‌های جدید بازنویسی می‌کند.

همانطور که اشاره کردم، اولین پارامتر ما مسیر به سمت است weatherdata.json فایلی که به writeFileSync مثل این: path.resolve(pathToData).

از آنجایی که ما از ماژول های ES استفاده می کنیم، __filename و __dirname به آسانی در دسترس نیستند. من بی شرمانه کد زیر را (از این منبع) برای ایجاد آن برش دادم و چسباندم pathToData متغیر.

const __filename = fileURLToPath(import.meta.url);

const __dirname = path.dirname(__filename);

const pathToData = path.join(__dirname, "weatherdata.json");
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

داشتن __dirname موجود به ما کمک می کند تا مسیر خود را پیدا کنیم weatherdata.json فایل.

که تمام تغییرات را به پایان می رساند scraper.js فایل، منهای عبارات واردات در بالا. من کل فایل را به اشتراک می گذارم تا خواندن آن راحت تر باشد.

import puppeteer from "puppeteer";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);

const __dirname = path.dirname(__filename);

const pathToData = path.join(__dirname, "weatherdata.json");

async function scrape() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  await page.goto(
    "https://www.weathertab.com/en/d/united-states/texas/austin/"
  );

  const weatherData = await page.evaluate(() =>
    Array.from(document.querySelectorAll("tr.fct_day"), (e) => ({
      dayOfMonth: e.querySelector("td > div.text-left > .fct-day-of-month")
        .innerText,
      dayName: e.querySelector("td > div.text-left > .fct-day-of-week")
        .innerText,
      weatherIcon: e.querySelector("td.text-center > .fct_daily_icon")
        .classList[1],
      weatherIconPercent: e
        .querySelector("td.text-center")
        .getElementsByTagName("div")[1].innerText,
      highTempRange: e.querySelector(
        "td.text-center > .F > div > .label-danger"
      ).innerText,
      lowTempRange: e
        .querySelector("td.text-center > .F")
        .getElementsByTagName("div")[1].innerText,
    }))
  );

  await browser.close();
  return weatherData;
}

// execute and persist data
scrape().then((data) => {
  // persist data
  fs.writeFileSync(path.resolve(pathToData), JSON.stringify(data, null, 2));
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

راه اندازی اکشن GitHub

هدف GitHub Action ما این است که منبع آب و هوا را به صورت هفتگی خراش دهیم و آخرین داده ها را در یک برنامه ذخیره کنیم. .json فایل.

اگر هرگز اقدامی ایجاد نکرده‌اید، من شما را از طریق مراحل راهنمایی می‌کنم.

ابتدا تب Actions را در مخزن GitHub خود پیدا کنید.

توضیحات تصویر

برای ورود به صفحه اقدامات کلیک کنید. در مرحله بعد، روی دکمه “جریان کاری جدید” کلیک کنید. با این کار صفحه ای از گزینه ها باز می شود، با این حال، ما فقط می خواهیم گزینه های “تنظیم گردش کار خود” را انتخاب کنیم.

توضیحات تصویر

با این کار وارد یک ویرایشگر می شوید. به راحتی می توانید نام فایل yaml را هر چه می خواهید بگذارید، یا آن را به عنوان main.yml بگذارید.

ادامه دهید و این را بچسبانید:

name: Resources
on:
  schedule:
    - cron: "0 13 * * 1"
  # workflow_dispatch:
permissions:
  contents: write
jobs:
  resources:
    name: Scrape
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - uses: actions/setup-node@v3
        with:
          node-version: 16
      - run: npm ci

      - name: Fetch resources
        run: node ./scraper.js

      - name: Update resources
        uses: test-room-7/action-update-file@v1
        with:
          file-path: weatherdata.json
          commit-msg: Update resources
          github-token: ${{ secrets.GITHUB_TOKEN }}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از چسباندن آن، می توانید فایل yml جدید را با کلیک بر روی دکمه “Start Commit” و وارد کردن پیام commit و غیره commit کنید.

بنابراین، در مورد این عمل باید به چند نکته توجه کرد:

  1. اکشن با استفاده از ویژگی cron بر اساس یک زمان بندی اجرا می شود. مقداری که من در اختیار دارم می گوید که این عمل هر دوشنبه در ساعت 1300 (13:00) راه اندازی می شود.
  2. مطمئن شوید که فایل جاوا اسکریپت شما با روش اسکرپ، scraper.js نام دارد، یا اگر اینطور نیست، اقدام را به روز کنید و نام فایل خود را جایگزین scraper.js کنید.
  3. ما در حال استفاده از test-room-7/action-update-file@v1 برای کمک به ما در به روز رسانی فایل scraper.js. اگر مایلید در مورد آن اقدام بیشتر بدانید، آنها را در GitHub جستجو کنید.

اگر ترجیح می دهید هر زمان که خواستید این اکشن را اجرا کنید، این دو خط را کامنت کنید یا حذف کنید:

schedule:
    - cron: "0 13 * * 1"
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و این خط را حذف کنید:

# workflow_dispatch:
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس دکمه ای را در جایی در قسمت اقدامات می بینید که به شما امکان می دهد هر زمان که مایلید کار را اجرا کنید. این برای آزمایش اقدامات خوب عمل می کند.

می توانید مخزن من را اینجا ببینید

نتیجه

من در این سریال خیلی چیزها یاد گرفتم. من از منطقه راحتی خود خارج شدم و توانستم کاری را انجام دهم. در طول مسیر موانعی وجود داشت، اما در پایان روز، همه چیز به این است که دستانم را کثیف کنم و چیزها را بفهمم. امیدوارم شما هم چیزی یاد گرفته باشید. اگر این پست ها را جالب، خسته کننده، کم، عالی و غیره دیدید…لطفا به من اطلاع دهید. متشکرم!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا