あいつの日誌β

働きながら旅しています。

ShiftJIS なサイトをスクレイピングしたい

という要望がいまだにあるとかないとか。とりあえずメタ情報を取得する場合はこんな感じになりました。

const scrapeIt = require('scrape-it');
const got = require('got')
const encoding = require('encoding-japanese')

async function main() {

  const url = "http://okamuuu.hatenablog.com/"  // ShiftJIS なサイトの URL を各自で探して見てください。
  const {body} = await got(url, {encoding: null})
  const detected = encoding.detect(body);
  const unicode = encoding.convert(body, {
    from: detected,
    to: 'UNICODE'
  })
  const html = encoding.codeToString(unicode)
  const result = await scrapeIt.scrapeHTML(html, {
    title: "title",
    metaInfos: {
      listItem: "meta",
      data: {
        name: { attr: "name" },
        content: { attr: "content" },
      }
    }
  })
  console.log(result)
}

main()

このようにhttp.request{encoding: null} オプションを渡してバイナリのまま取得するとその後の処理が楽です。おしまい。

Storybook for React Native v4.0.2 を動かした時のメモ

expo と React Storybook for React Native を使った時の備忘録です。

Expo

expo は以下のコマンドで使えるようになります。

npm install -g expo-cli

expo を使って iOSエミュレータを起動したりするなどできます。

expo init AwesomeProject
cd AwesomeProject
npm start

Storybook for React Native

さて、既存の React Native のプロジェクトが出来たので以下のドキュメントを参考にして Storybook を追加します。

https://storybook.js.org/basics/guide-react-native/

なんですが、ドキュメントには不備があり、以下の Error と Warning が発生します。

ReferenceError: Can't find variable: React
Missing 'module' parameter for story with a kind of 'CenteredView'. It will break your HMR

少しドキュメントが不明瞭だったので以下に実際にした作業を記します

Can't find variable: React

storybook/stories/index.jsimport React from 'react'; を追加します

import { storiesOf } from '@storybook/react-native';
+ import React from 'react';
import { View, Text } from 'react-native';

Missing 'module' parameter for story with a kind of 'CenteredView'. It will break your HMR

storybook/stories/index.js の storiesOf の引数に module を追加します。

-storiesOf('CenteredView')
+storiesOf('CenteredView', module)

entry app

expo の場合だと App.js を以下のように書き換えます。

import StorybookUI from './storybook';
export default StorybookUI

これで動作すると思います。

それから

一応PRしておきました。もし同じようなエラーメッセージが出てしまった場合は参考にして見てください。

https://github.com/storybooks/storybook/pull/4680

追記: merge されました。

Nuxt.js で buefy を試す方法 version 2018-10-11

あらすじ

いくつかハマった点があったのでメモ

vue init nuxt-community/starter-template

以前記事にもしましたが isClient というメソッドは現在ご利用できません。

vue init nuxt-community/starter-template practice-nuxt-buefy && cd $_  
yarn

nuxt.config.js を以下のように修正します。

-    extend (config, { isDev, isClient }) {
-      if (isDev && isClient) {
+    extend (config, { isDev }) {
+      if (isDev && process.client) {

動作確認

yarn run dev

buefy

上記のプロジェクトに buefy を追加します。

yarn add buefy

add plugin: create plugins/buefy.js

import Vue from 'vue';
import Buefy from 'buefy';
import 'buefy/dist/buefy.css';

Vue.use(Buefy);

edit nuxt.config.js

         })
       }
     }
-  }
+  },
+  plugins: [
+    { src: '~plugins/buefy', ssr: false }
+  ],
 }

どうやら buefy が内部で File オブジェクトを使用してるようですが、これは Node.js にはない、ブラウザのみのインターフェースなので ssr: false にしないと最初のリクエスト(一番最初のレンダリングは Node.js 側で行う)で以下のようなエラーが発生します。

error ReferenceError: File is not defined

こちらからは以上です。

Github API で自分が作業した内容をとりだすスクリプト

作業内容の報告書を書く時に URL が必要になったので書いた。

const axios = require('axios')
const qs = require('qs')
const moment = require('moment')

const BASE_URL = 'https://api.github.com/'
const TOKEN = 'YOUR_TOKEN'

async function getCommits(owner, repo, queryParams) {
  
  const q = qs.stringify(queryParams)

  return axios.create({
    baseURL: BASE_URL,
    timeout: 3000,
    headers: {
      'Authorization': `token ${TOKEN}`,
    },
  }).get(`/repos/${owner}/${repo}/commits?${q}`).catch(console.error)
}

async function main() {
  const res = await getCommits('okamuuu', 'practice-rails-app-docker', {
    author: 'okamuuu',
    since: moment().add(-90, 'days').format('YYYY-MM-DDTHH:MM:SSZ'),
    until: moment().format('YYYY-MM-DDTHH:MM:SSZ')
  });

  const commitObjects = res.data

  const commitsOf = {}
  commitObjects.forEach(obj => {
    const date = moment(obj.commit.author.date).format('YYYY-MM-DD');
    if (commitsOf[date] === undefined ) {
      commitsOf[date] = []
    }
    commitsOf[date].push(obj.html_url);
    // console.log(obj.commit.author.date)
    // console.log(obj.commit.url)
  })

  for (let date in commitsOf) {
    console.log(date)
    const commits = commitsOf[date]
    console.log(commits.join("\n"))
  }
}

main();

access_token の取得方法は Creating a personal access token - GitHub Docs を参照。

実行結果。

2018-08-21
https://github.com/okamuuu/practice-rails-app-docker/commit/f8eeac0d87e31e20bbfbca6d3b0c6e18c6225d62
https://github.com/okamuuu/practice-rails-app-docker/commit/2f3fe1f253962842cd010988714e1c98c007b5f3
https://github.com/okamuuu/practice-rails-app-docker/commit/c95d453762be8dc2aa95cab3af2ab4ca517f0a29
https://github.com/okamuuu/practice-rails-app-docker/commit/352e50785ae218f555d91cbe3d72eabed474faf4
https://github.com/okamuuu/practice-rails-app-docker/commit/69adab4e9c1b547a1a1a9c73764fe66c0ccf3671
https://github.com/okamuuu/practice-rails-app-docker/commit/111021a00eed75ca0b7beec0c249275c767d273c
https://github.com/okamuuu/practice-rails-app-docker/commit/397974b760a87cca2f4faeeb7d19fe70a8ec1d8f
https://github.com/okamuuu/practice-rails-app-docker/commit/1e45ad2fe316336e22a026c6bedde8db674d593a
https://github.com/okamuuu/practice-rails-app-docker/commit/6e6fb4a943e7074db71dbbec5398f7bc4c2c1f73
https://github.com/okamuuu/practice-rails-app-docker/commit/c4e7ca1f2618bf77743cbb780e3e8b632d7fd789
https://github.com/okamuuu/practice-rails-app-docker/commit/64bd5a4200eb4a46bd3ca08e641e49249b604466
https://github.com/okamuuu/practice-rails-app-docker/commit/79a497d98a4771e602abac7f5d0b4a810f95b354
https://github.com/okamuuu/practice-rails-app-docker/commit/cab4949876176986108a909da0fe8eecc6bc3fce
2018-08-20
https://github.com/okamuuu/practice-rails-app-docker/commit/4c5659e87401a12a010478747fb973772460fa1d
https://github.com/okamuuu/practice-rails-app-docker/commit/3ca6b776830ba71f4b981b40a10c9c47d62dac57
https://github.com/okamuuu/practice-rails-app-docker/commit/4d2e4cca9a358252d309dea41d19594dcdb76e19
https://github.com/okamuuu/practice-rails-app-docker/commit/ae721effdb9d81943e9b002d9db89a522de0e51e
https://github.com/okamuuu/practice-rails-app-docker/commit/960e652dd1af962543ef07e13ec932c9a0fd1893
https://github.com/okamuuu/practice-rails-app-docker/commit/b4ea70149edae79ae5edf49bb76269d6d3dbd9c0
https://github.com/okamuuu/practice-rails-app-docker/commit/6a2c20a69655bf4e3e87666d11655d75e5e9df96
https://github.com/okamuuu/practice-rails-app-docker/commit/0976b5773c743a301f1fc249aec87d9fc0c90ddc
https://github.com/okamuuu/practice-rails-app-docker/commit/96e3678374f3fd2a7f2689683abeb8440378ca99
https://github.com/okamuuu/practice-rails-app-docker/commit/6a72b60c7ab0bfeb34bd84fdf10e57e432af5a48
https://github.com/okamuuu/practice-rails-app-docker/commit/ea4d1f2547fe0e5932254cc9c64942fb8a7b0c0a
https://github.com/okamuuu/practice-rails-app-docker/commit/d3ffe90738e7219e294736ecc82cf63623022d6b

表示する内容は以下を参考にして各自で調整するとよいでしょう。

developer.github.com

Nuxt.js で yarn run dev で TypeError: Cannot read property 'eslint' of undefined と言われる場合の対処

以下のように nuxt.js を始めようと思った時に

vue init nuxt-community/starter-template my-project 
cd my-project
yarn
yarn run dev

http://localhost:3000 にアクセスすると以下のようなエラーが表示される

ERROR in ./.nuxt/client.js
Module build failed (from ./node_modules/eslint-loader/index.js):
TypeError: Cannot read property 'eslint' of undefined
    at Object.module.exports (/Users/okamuuu/prj/practice/my-project/node_modules/eslint-loader/index.js:148:18)

どうやら nuxt.config.js の isClient が deprecated として前から警告されており、使用できなくなったようです。

https://github.com/nuxt/nuxt.js/issues/2527

という事で以下のように修正しましょう。

-    extend (config, { isDev, isClient }) {
-      if (isDev && isClient) {
+    extend (config, { isDev }) {
+      if (isDev && process.client) {

めでたし。

岡山城天守閣でライトニングトークして来ました

天守閣でLTした。ただそれを言いたかった。

f:id:okamuuu:20180929213112j:plain

とある pm で開催が発表された

主に八王子で開催される怪しいエンジニアが集まる会があるのですが、そこに参加した日に主催者より「天守閣でテックカンファレンスを開く」と発表がありました。*1

https://connpass.com/event/98976/

connpass.com

というわけで岡山城

f:id:okamuuu:20180930111911j:plain

日程の関係上私は第二部から参戦しました。主催者より「何かを破損させたものは斬る」とのお達しが告げれた後、宴が始まりました。

天守閣にて

f:id:okamuuu:20180930112034j:plain

第二部が始まってからすぐに「最上階で飲まねば!」という事で天守閣での飲酒一番乗りを果たしました。

LT

その後何名か同じ事を考えている人がいたので天守閣で飲んでいたらLTが始まっており、LT を聞き逃してしまったので今回聞いたLTは以下の3つだけ

  • makamaka - せっかくだから俺はこの杓文字2.0で同人誌をつくるぜ
  • codehex - 侍が作る1ボタンキーボード
  • catatsuy - ISUCONの情報共有にはこれ!notify_slack!

makamaka

Acme モジュールの話。Acme::Math::Josan っていう josan(12, 4) を実行すると 3 か 48 が返って来るっていう、乗算なの?除算なの?っていうモジュールや土一揆する時に便利なモジュールなどを紹介。

codehex

電子工作でキーボードを作成する話。モールス信号(2進法)でキーボード作りました!でも家に忘れて来ました!なので急遽徹夜で作りました!動きませんでした!

期待感と勢いのあるトークで最後結局動かなかったというオチまでとてもライトニングトークらしくて聞いててとても楽しかったです。

catatsuy

ISUCON の実力者が使っているツールの紹介。サーバー側で出力される文字列をそのまま slack に流して情報共有したい人には便利。どうやら負荷が高くならないように1秒間に一度だけまとめて Slack API に POST したりだれが操作したコマンドのログなのかが分かるといった便利機能があって良さげ。チームで戦うには情報共有大事ですよねえ。

okamuuu(私)

Contentful という Headless CMS を使ったので感想を述べました。だんだんサーバーサイドでコード書かなくても開発ができる時代が来ている気がします。全く不要というわけにはいかないと思いますが、手を動かす時間が減っていく予感。

https://speakerdeck.com/okamuuu/2018-09-29-dot-okayama

台風襲来したけど楽しかった

そんなわけで翌日台風がやって来るので飛行機や新幹線が無事動いたのかどうなのか定かではないのですが、みなさん無事に帰れるといいですね。

というわけで今回お城を借りて頂いた主催者のお陰で楽しい1日を過ごす事ができました。聞くところによると予約してから開催するまでのやりとりが結構大変だったらしいです。*2

あと岡山城を貸す側も実際に城を貸したら乱暴に扱う人も稀にいるらしく、貸す側も借りる側も結構大変だったと思います。運営してもらった人たちに感謝です。

*1:岡山城天守閣を貸切で利用

*2:基本的に電話かFAX