Magento の Security Updates をスクレイピングしたい

## はじめに

本投稿は、規約違反を促すものではありません。規約は熟読し、厳守するようにしましょう。

## 何がしたいか

Magento は越境 EC のプラットフォーム・ソフトウェアで、癖がすごいのでできれば遠慮したいが、他に有力な選択肢もあまりない感じのシステムだ。そして私には Magento やめるという決定権はないので、Magento と付き合っていく必要がある。

Magento は広く使われているため、攻撃対象になりやすく、Security Updates は見逃してはならない。嘘でしょ、やばーみたいな Update がちょいちょい来る。

Magento だけであれば、

[Security Updates for Magento](https://helpx.adobe.com/security/products/magento.html)

をチェックしていれば良いのだが、RSS フィードのようなものもないし、Blog や X は、Magento のセキュリティだけを抽出したい私には、ほぼ必要ない情報で満たされているため使えない。[Security Notificatoin Service](https://www.adobe.com/subscription/adbeSecurityNotifications.html) があるけど、メール…

定時チェックして更新があったら Slack などに通知するようにしたい。スクレイピングか。

## 先に結論

スクレイピングしちゃダメ。

[アドビ基本利用条件](https://www.adobe.com/jp/legal/terms.html)
> 6. ユーザーの行動基準
> お客様は、本サービスおよび本ソフトウェアを責任を持って使用する必要があります。本サービスおよび本ソフトウェアを不正使用しないでください。例えば、以下の行為を行ってはなりません。
> ...
> 6.18 本サービスおよび本ソフトウェアに関連して、データマイニングや同様のデータ収集および抽出方法を使用すること（機械学習をはじめとする目的のためのデータスクレイピングなど）。

ちょっと曖昧なので、英語原文

> 6.18 use any data mining or similar data gathering and extraction methods in connection with the Services and Software, including data scraping for machine learning or other purposes; 

ダメですね。解散。


## スクレイピングの技術検証

やっちゃダメなので、やっちゃダメなんですが、当初、robots.txt を見て大丈夫そうだなーと思って実装してみたところ、WAF に割とブロックされ、WAF 超えに夢中になってしまったのだけど、やっぱ何かおかしいと規約をあたってみた（問い合わせてみた）ら、ダメだった。でも、もうものはできちゃったという感じなので、やったことのメモとして残すことにする。こうすればできるのでやりなよという記事ではない。Closed の InHouse だけだから良いということにもならない。

以下では、コピペで動くようなコードの全容は割愛する。

### 要件
- [Security Updates for Magento](https://helpx.adobe.com/security/products/magento.html) をスクレイピングする
- 新規投稿・更新があったものを検知した場合、Slack に通知
- GitHub Actions などで動かす（ローカルではなくサーバにデプロイして動かす）

### Google Apps Script

久しぶりの GAS。やってみたいことがあった。スクレイピングなんてかったるいし、Gemini にやってもらえば良いんじゃね？

> [「Googleスプレッドシート × Gemini AI」でもう手作業はいらない！業務効率化の最強テクニック](https://qiita.com/sasajimay/items/f4970570c29e3d88071e)

上記の記事のコードはほぼそのままに、プロンプトだけ変えて実行。結果…

> I am unable to access external websites or specific databases in real-time.

ダメでした。良いと思ったんだけどなー。残念。GAS x Gemini は、他に使い道がありそうなので、無駄ではなかったとする。

気を取り直して、GAS でスクレイピングする実装をしてみたところ… なんかコンテンツがうまく取得できない、自分のサイトをやってみると普通に取得できるけど、できない。curl では取得できるし、変にリダイレクトしてたりもしない。robots.txt では、特に禁止されていない。では、何故？

このあたりで、GAS のエディタが vim じゃないことに耐えかねて、ローカルの JavaScript で開発することに。

### Puppeteer（ダメでした）
Puppeteer は、雑に説明すれば、ほぼ Chrome だ。Chrome を立ち上げて中身を取ってくる。GUI のない環境でも動くように `headless: true` というオプションが設定ができる。

```javascript
const puppeteer = require("puppeteer");

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  const url = "https://helpx.adobe.com/security/products/magento.html";
  await page.goto(url, { waitUntil: "domcontentloaded", timeout: 60000 });
  // 処理
  ...
  await browser.close();
})();
```
レスポンス返ってきませんでした。
要件を満たさないけど、headless をやめて、UA を偽装してなどしたらどうか？を試してみることに。（GitHub Actions などで動かす場合、`headless: true` が必要）

```javascript
(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    args: [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-blink-features=AutomationControlled",
      "--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
    ],
  });
  ...
})();
```

これだとコンテンツを取得することができました。WAF で headless ブラウザをブロックしてるっぽいですね。

### Playwright（ダメでした）
Playwright は、Microsoft が開発したブラウザ自動操作ライブラリで、雑に説明すると、上位互換の Puppeteer みたいなものです。E2E テストなどで使われる事例も多く、WAF 耐性も強いらしいです。

つまり、`headless: true` でも WAF を突破できるかも。ということで試してみました。

```javascript
const { chromium } = require("playwright");

(async () => {
  const browser = await chromium.launch({ headless: true });
  const page = await browser.newPage();
  const url = "https://helpx.adobe.com/security/products/magento.html";
  await page.goto(url, { waitUntil: "domcontentloaded", timeout: 60000 });
  // 処理
  ...
  await browser.close();
})();
```

実行してみたところ… ダメでした。

```
page.goto: net::ERR_HTTP2_PROTOCOL_ERROR at https://helpx.adobe.com/security/products/magento.html
```

どうやら Adobe の headless browser 検知は普通には乗り越えられなさそう。

ここで、Playwright のステルス化を検討したが、公式に Plugin がない、一部有料などハードルが高いので、保留に。なお、後述の Puppeteer のステルス化でできるので、Playwright でもきっとできる。

### Stealth Puppeteer（できました）

Puppeteer の StealthPlugin でステルス化する。
このプラグインは、

- navigator.webdriver -> false
- Chrome header 整合性
- TLS 指紋のカモフラージュ

などを勝手にやってくれる。らしい。

```javascript
const puppeteer = require("puppeteer-extra");
const StealthPlugin = require("puppeteer-extra-plugin-stealth");

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    args: [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-blink-features=AutomationControlled",
    ],
  });

  const page = await browser.newPage();
  // 念の為UAを再度設定
  await page.setUserAgent(
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
      "AppleWebKit/537.36 (KHTML, like Gecko) " +
      "Chrome/122.0.0.0 Safari/537.36"
  );

  const url = "https://helpx.adobe.com/security/products/magento.html";
  await page.goto(url, { waitUntil: "domcontentloaded", timeout: 60000 });
  // 処理
  ...
  browser.close()
})();
```

これで headless でもコンテンツを取得できました。slack の通知まで実装すると、

![Screenshot 2025-03-25 at 15.53.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245908/1cb2cbf7-c51d-4cad-883b-37989fda358e.png)

こんな感じで欲しかったものが実現できる。こういうのが忘れた頃に飛んでくる夢を見たんだけど、儚かった。

## まとめ

規約で明確にスクレイピングするなと書いてあるので、Adobe のサイトをスクレイピングするのはやめましょう。ML でなんて、いつの時代の通知方法よ！？もしくは、その発想はなかったわ！と思う人が大半な2025年では、Adobe に置かれましては、もうちょっとまともな通知方法を設置していただきたい。

当初目的の Security Updates for Magento のスクレイピング定期実行は、規約で禁止されていたので諦めたが、規約で禁止されておらず、robots.txt でも禁止されておらず、でも WAF が headless browser をブロックしているような場合、今回検証した Puppeteer のステルス化などでスクレイピングすることは可能だ。

また、ディフェンスの立場として、Adobe の WAF のように headless browser (bot）対策を検討・導入してみるのも良い。

なお、Adobe Magento Commerce Cloud 上で動いている我らの Magento の WAF は、こちらが設定しているものとは別に Adobe が勝手に良い感じに追い WAF してくれてたりするのかしら？と思って調べてみたが、非常に残念な結果となった。

頼むよ、Adobe さん！とみんなでしつこくお願いしましょう。