$shibayu36->blog;

株式会社アンドパッドでエンジニアをしています。プログラミングや読書のことなどについて書いています。

puppeteerを使って最近の自分のブログのサマリーを出す

評価時期で自分のアウトプットの様子を出す必要があり、この機会にTypeScript + puppeteerでシュッとスクレイピングするの試してみるかと思い、やってみた。

完成したもの

https://github.com/shibayu36/tools/blob/a7156bc03620700105cc52e54d69cac38b13f40e/script/blog-ranking.ts

スクリプト内でurls, start, endを定義しておくと、特定期間の総記事数や総ブックマーク数、記事の情報を出してくれるようになった。

使い方は

git clone https://github.com/shibayu36/tools.git
cd tools
npm install
npx ts-node script/blog-ranking.ts

コード

/* eslint-disable @typescript-eslint/no-non-null-assertion */
import axios from "axios";
import { parse, parseISO, isBefore } from "date-fns";
import { sumBy, sortBy } from "lodash";
import puppeteer from "puppeteer";

const start = parseISO("2020-07-01T00:00:00+09:00");
const end = parseISO("2021-01-01T00:00:00+09:00");
const urls = [
  "https://blog.shibayu36.org/archive/category/tech",
  "https://blog.shibayu36.org/archive/category/tech?page=2",
];

async function main(): Promise<void> {
  const browser = await puppeteer.launch();
  const articlesList = await Promise.all(urls.map((u) => fetchArticles(browser, u)));
  const articles = articlesList.flat().filter((a) => isBefore(start, a.date) && isBefore(a.date, end));

  console.log("総記事数:", articles.length);
  console.log("総ブックマーク数:" + sumBy(articles, "bookmark"));
  for (const a of sortBy(articles, [(a) => -a.bookmark])) {
    console.log(`[${a.title} ${a.url}]`, a.bookmark);
  }

  await browser.close();
}

type ArticleWithBookmark = {
  title: string;
  url: string;
  date: Date;
  bookmark: number;
};
async function fetchArticles(browser: puppeteer.Browser, url: string): Promise<readonly ArticleWithBookmark[]> {
  const page = await browser.newPage();
  await page.goto(url);
  const articles = await page.evaluate(() => {
    const articleElements = Array.from(document.querySelectorAll(".archive-entry"));
    return articleElements.map((elem) => {
      const link = elem.querySelector(".entry-title-link")!;
      const title = link.textContent!;
      const url = link.getAttribute("href")!;
      const date = elem.querySelector(".archive-date time")!.getAttribute("datetime")!;
      return {
        title,
        url,
        date,
      };
    });
  });
  page.close();

  const queries = new URLSearchParams();
  for (const article of articles) {
    queries.append("url", article.url);
  }
  const res = await axios.get<{ [url: string]: number }>(
    `https://bookmark.hatenaapis.com/count/entries?${queries.toString()}`
  );

  return articles.map((a) => ({
    title: a.title,
    url: a.url,
    date: parse(a.date, "yyyy-MM-dd", new Date()),
    bookmark: res.data[a.url] ?? 0,
  }));
}

main().catch((error) => console.error(error));

最近のブログの様子を出した

2020/07~2020/12の様子を出した。総記事数35、総ブクマ数4184と結構頑張れたと思う。「締め切りが厳しいプロジェクトで、プロジェクト初期にまずやっておきたいこと」という記事はこれまでやってきたプロジェクトマネジメントの経験を言語化できて良かった。

blog.shibayu36.org

総記事数: 35
総ブックマーク数:4184
[締め切りが厳しいプロジェクトで、プロジェクト初期にまずやっておきたいこと https://blog.shibayu36.org/entry/2020/07/27/181500] 1077
[メンターを初めて経験する人に、最初に読むものとしてオススメしている書籍たち https://blog.shibayu36.org/entry/2020/07/10/183000] 872
[部下の困りごとをマネジャーが解決しすぎない方が良い https://blog.shibayu36.org/entry/2020/11/20/180000] 471
[TypeScriptの型を手に馴染ませるためにやっていること https://blog.shibayu36.org/entry/2020/10/15/173000] 390
[現代のソフトウェア開発を学ぶために「正しいものを正しくつくる」を読んだ https://blog.shibayu36.org/entry/2020/08/17/181500] 354
[開発チームの責務を「エンジニアリング観点でのサービス継続リスクをコントロールしながら、開発速度を最大化する」としてみた話 https://blog.shibayu36.org/entry/2020/10/01/180000] 203
[今見ているファイル内をSearchしやすくするVSCode拡張を作りました https://blog.shibayu36.org/entry/2020/07/06/180000] 169
[PullRequestからチーム開発の生産性・健全性を測るCLIツールを書いてみた https://blog.shibayu36.org/entry/2020/08/24/173000] 141
[VSCodeのFindで今マッチしている場所にボーダーを引いて見やすくする https://blog.shibayu36.org/entry/2020/10/12/180000] 120
[開発チーム運営では問題発見・改善だけでなく、良かったことの共有も大事にする https://blog.shibayu36.org/entry/2020/07/28/183000] 65
[TypeScriptでCLIツール作りをするためのプロジェクトサンプルを作ってみた https://blog.shibayu36.org/entry/2020/08/05/183000] 47
[長い期間、継続的にブログを書き続けるための工夫 https://blog.shibayu36.org/entry/2020/07/15/183000] 40
[ALBで特定のpathのときだけCognito認証を通す構成をaws-cdkで作る https://blog.shibayu36.org/entry/2020/09/23/180000] 39
[GitHub Actionsでeslintを動かすだけでFiles changedにlint errorが表示されて便利 https://blog.shibayu36.org/entry/2020/11/09/173000] 36
[特定のファイルだけgit stashする https://blog.shibayu36.org/entry/2020/07/17/105146] 30
[VSCodeのExplorerでフォーカスしているファイルを、ActiveなEditor Groupの隣に開く拡張を作った https://blog.shibayu36.org/entry/2020/10/28/183000] 29
[workflow_dispatchを使うとGithub Actionsのデバッグも楽だった https://blog.shibayu36.org/entry/2020/07/22/114015] 24
[Jamboardを使ってオンラインでプラニングポーカーをする https://blog.shibayu36.org/entry/2020/09/02/170308] 17
[VSCodeの置換でEmacs風の挙動を再現する https://blog.shibayu36.org/entry/2020/10/02/180000] 16
[他人を動かすコミュニケーション手法を学ぶ - 「人を動かす」読んだ https://blog.shibayu36.org/entry/2020/12/08/180000] 13
[「デッドライン」読んだ https://blog.shibayu36.org/entry/2020/11/16/183000] 5
[PullRequestの統計情報をBigQueryに送り、変更のリードタイムを柔軟に可視化する https://blog.shibayu36.org/entry/2020/10/27/183000] 5
[開発効率化のために最近入れたツールたち(indent-rainbow / TabNine / Tree Style Tab / Clipy) https://blog.shibayu36.org/entry/2020/08/31/183000] 5
[「ピープルウェア 第3版」読んだ https://blog.shibayu36.org/entry/2020/11/13/180000] 3
[スプレッドシートで保育園の在庫管理をしようとして失敗したけど、claspによるGASの管理方法を学べた https://blog.shibayu36.org/entry/2020/09/08/183000] 3
[「プロジェクトマネジメントの基本」読んだ https://blog.shibayu36.org/entry/2020/11/17/183000] 2
[GraphQL APIを使って、特定のGitHub Teamが持つレポジトリ一覧を一発で取得する https://blog.shibayu36.org/entry/2020/11/03/173000] 2
[「MBAより簡単で英語より大切な決算を読む習慣」読んだ https://blog.shibayu36.org/entry/2020/07/07/180000] 2
[VSCodeにAwesome Emacs Keymap入れた https://blog.shibayu36.org/entry/2020/11/02/183000] 1
[ReactのuseEffect/useLayoutEffectやレンダリングの実行順について調べた https://blog.shibayu36.org/entry/2020/09/24/180000] 1
[開発チームのパフォーマンスを測る指標を学ぶ - 「LeanとDevOpsの科学」読んだ https://blog.shibayu36.org/entry/2020/09/07/183000] 1
[スクラムガイド(2017)読んだ https://blog.shibayu36.org/entry/2020/07/22/183000] 1
[「リモートワークの達人」読んだ https://blog.shibayu36.org/entry/2020/12/01/183000] 0
[TypeScriptプロジェクトのテストとlintをGitHub Actionsで実行する https://blog.shibayu36.org/entry/2020/08/25/180000] 0
[SCRUM BOOT CAMP THE BOOK【増補改訂版】を読んだ https://blog.shibayu36.org/entry/2020/07/29/183000] 0

他人を動かすコミュニケーション手法を学ぶ - 「人を動かす」読んだ

最近どのようにすればチーム内や組織内に良い変化を与えることが出来るのか悩んでいた。とにかく自分でやったら良い系だと簡単なのだけど、他の人にも積極的に協力してもらう必要があるものについては難しい。そのような時にも、うまくやる手法を学ぶために「人を動かす」を読んでみた。

人を動かす 新装版

人を動かす 新装版

昔から良い本であることは聞いていたけれど、読んでみると思っていた以上に良くて、「全て書いてあるとおりです、すいませんでした」という気持ちになりながら読んだ。読んでみると1on1やコードレビュー、プロジェクトマネジメントの良いやり方にも繋がってきて、背景にこういうものがあるのだなと腹落ちできた。

特に「人を動かす三原則」「人を説得する十二原則」の章が参考になった。例えば人を動かす・説得するために気にしておくことを自分の手元に箇条書きで書き留めたのだが、これまでの自分の経験に照らし合わせても、そうだなあと思うことが多い。

  • 人に指摘・非難しても人は動かない。人を褒めることでしか人は動かない。
  • 人を非難する代わりに、相手を理解するように努める。どういうわけで、相手がそんなことをしでかすに至ったか、よく考えてみる。
  • 他人の長所を考え続け、どんな小さいことでもほめる
  • 説得する前に「どうすれば、そうしたくなる気持ちを相手に起こさせることができるか?」と自分に問う
  • 議論に負けても、その人の意見は変わらないので、議論を避ける
  • 他人の間違いを指摘しない
  • 「私の間違いかもしれませんが」から話し始める
  • 「絶対に」「疑いもなく」のような断定的な物言いをやめ、「自分としてはこう思うのだが」という言い方を使う。 相手が明らかに間違っていても、「なるほどそういう場合もあるだろうが、しかしこの場合は少し事情が異なるのではないか」という言い方をする
  • 自分が間違っているときはすみやかに自分の誤りを快く認める
  • 喧嘩腰で話さず、穏やかに話す
  • エスと答えられる問題から話し始める。意見が一致している問題からはじめ、互いに同一の目的に向かって努力しているのだということを、相手に理解させるようにし、違いはただその方法だけだと強調する
  • 相手のいうことに異議を挟みたくなっても、我慢する。相手が言いたいことをまだ持っている限り、こちらが何を言っても無駄。
  • 相手に思いつかせる。 暗示を与えて、結論は相手に出させる
  • 「もし自分が相手だったら、果たしてどう感じ、どう反応するだろうか」と自問自答する。原因に興味を持てば、結果にも同情を寄せられるようになる
  • 期待をかける。どこかいいところを見つけて、それへ敬意を表し、期待の言葉を与える

今後は以上のメモを意識して他の人とコミュニケーションしていきたいなと思う。

「リモートワークの達人」読んだ

最近ほとんど全員がリモートで働くことになり、今までのやり方ではそこそこ困っているので読んだ。

「いやな言葉」「感情的な対立」「悪いムード」を徹底的に排除する

という部分が非常に良い言葉だなあと思う。

読書ノート

* 毎日4時間はみんな同じ時間に働いたほうが良い。コミュニケーションもうまくいくし、チームの一体感が出る 688
    * 気づき: フレックスのコアタイムも4時間は被せる
* 進み具合を共有するために、週に一度「最近やっていること」というテーマで話し合いの場を設ける。この1週間でやったことと翌週にやることを手短に書き込んでいく 788
    * 気づき: 書き込みでやっていくの、スプリント会に導入しても良いかも
* リモートとは単に遠隔地という意味ではなく、時間と場所に縛られない働き方 814
* リモートで世界的な視野を手に入れれば、顧客によりよいサービスを提供することに繋がる 1087
    * 気づき: 多様性を上げやすくなるということかな
* リモートだとむしろチームの雰囲気を盛り上げてくれるような人柄が重要になる 1133
    * 文字だけでやり取りする時、人は悪い方に流されやすくなる
* リモートワークをマネジメントするときは、棘のあるコメントや逆ギレの反応などの小さな行動をひとつひとつ注意していく。割れ窓にならないように 1142
    * 最終的に社員全員がおたがいに指摘できるようになると効果的
    * 「いやな言葉」「感情的な対立」「悪いムード」を徹底的に排除する 1151
* 地域で賃金差別をしない 1211
    * 気づき: 家賃手当とかでも同じようなことになるので注意する
* 候補者の仕事ぶりを知るためのベストな方法は、本格的に採用する前に1~2週間お試し採用をして、給料を払い、小さなプロジェクトをやりとげてもらうこと 1284
    * 現在働いているなら副業的にやってもらうでも良い
* リモートでは働きすぎをふせぐため、あえて休暇を増やすなどをする必要がある 1536