POPWEB https://blog.popweb.dev Developer, Blogger, Illustrator in Tokyo. Mon, 17 Jul 2023 13:12:03 +0000 ja hourly 1 https://wordpress.org/?v=6.7.6 https://storage.googleapis.com/gcs.pop-web.net/2021/01/favicon.ico POPWEB https://blog.popweb.dev 32 32 window.top === window.selfは何をしているのか? https://blog.popweb.dev/programming/javascript/window-top-window-self/ https://blog.popweb.dev/programming/javascript/window-top-window-self/#respond Tue, 04 Jan 2022 13:48:00 +0000 https://blog.popweb.dev/?p=1745 プロジェクトで「if (window.top === window.self) {…}」という条件式を初めて見たので、その意味を調べてみました。 この条件式は、開いているページがiframeで読み込んだページを表示してい […]

The post window.top === window.selfは何をしているのか? first appeared on POPWEB.]]>
プロジェクトで「if (window.top === window.self) {…}」という条件式を初めて見たので、その意味を調べてみました。

この条件式は、開いているページがiframeで読み込んだページを表示しているかどうかを判定するためのものです。

window.topは、最上位のコンテキスト(ウィンドウ)を返します。iframe要素を複数埋め込んでいる場合でも、一番上の親ウィンドウを取得することができます。

一方、window.selfは現在のウィンドウ自身を返します。

したがって、iframeがないページではwindow.selfwindow.topは等価になります。これを利用して、ページがiframeを含むかどうかを判定することができます。

The post window.top === window.selfは何をしているのか? first appeared on POPWEB.]]>
https://blog.popweb.dev/programming/javascript/window-top-window-self/feed/ 0
林の中の象のように… https://blog.popweb.dev/kingen/%e6%9e%97%e3%81%ae%e4%b8%ad%e3%81%ae%e8%b1%a1%e3%81%ae%e3%82%88%e3%81%86%e3%81%ab/ https://blog.popweb.dev/kingen/%e6%9e%97%e3%81%ae%e4%b8%ad%e3%81%ae%e8%b1%a1%e3%81%ae%e3%82%88%e3%81%86%e3%81%ab/#respond Thu, 02 Dec 2021 02:35:54 +0000 https://blog.popweb.dev/?p=1737 聡明な伴侶を得られるのなら共に歩め 聡明な人と歩めないのなら一人歩め 愚かなものを道連れとするな。 孤独に歩め、悪を為さず 求めるところは少なく、林の中の象のように これはブッタの言葉である。 自分なりに解釈してみたら、 […]

The post 林の中の象のように… first appeared on POPWEB.]]>
聡明な伴侶を得られるのなら共に歩め

聡明な人と歩めないのなら一人歩め

愚かなものを道連れとするな。

孤独に歩め、悪を為さず

求めるところは少なく、林の中の象のように

これはブッタの言葉である。

自分なりに解釈してみたら、以下のような感じ。

理想のパートナーが見つけられたならそれでいいが、そうでない人と共に歩んでいくと自らを堕落させてしまう。

それならば、林の中に佇んでいる象のように、気高く自信を持って自らの道を歩んでいけ。

The post 林の中の象のように… first appeared on POPWEB.]]>
https://blog.popweb.dev/kingen/%e6%9e%97%e3%81%ae%e4%b8%ad%e3%81%ae%e8%b1%a1%e3%81%ae%e3%82%88%e3%81%86%e3%81%ab/feed/ 0
【初心者解説】React.memo, useMemo, useCallbackとは? https://blog.popweb.dev/programming/react/%e3%80%90%e5%88%9d%e5%bf%83%e8%80%85%e8%a7%a3%e8%aa%ac%e3%80%91react-memo-usememo-usecallback%e3%81%a8%e3%81%af%ef%bc%9f/ https://blog.popweb.dev/programming/react/%e3%80%90%e5%88%9d%e5%bf%83%e8%80%85%e8%a7%a3%e8%aa%ac%e3%80%91react-memo-usememo-usecallback%e3%81%a8%e3%81%af%ef%bc%9f/#respond Tue, 23 Nov 2021 09:36:56 +0000 https://blog.popweb.dev/?p=1724 Ractには、メモ化するhookが用意されている。 そもそもメモ化とは? メモ化とは関数実行後の結果をキャッシュか何か保存しておくことによって、再度同じ関数を実行するのではなく、保存しておいた結果を返すこと。それによって […]

The post 【初心者解説】React.memo, useMemo, useCallbackとは? first appeared on POPWEB.]]>
Ractには、メモ化するhookが用意されている。

そもそもメモ化とは?

メモ化とは関数実行後の結果をキャッシュか何か保存しておくことによって、再度同じ関数を実行するのではなく、保存しておいた結果を返すこと。それによって実行速度を高速化させるためのものである。

Reactのパフォーマンスを最適化する

Reactはコンポーネントのpropsやstateが更新されると、その配下の全ての子コンポーネントも再レンダリングされる。

そのため、不要な再計算や再レンダリングを抑えるとことでパフォーマンスを最適化することができる。

その最適化の方法が、メモ化がである。

メモ化を実現する方法としてReact.memo useMemouseCallbackがある。

メモ化の対象するものがそれぞれ異なる。

  • React.memo: コンポーネントをメモ化するReactのAPI
  • useMemo: 計算結果をメモ化するHook
  • useCallback: コールバック関数をメモ化するHook

React.memo

React.memoを利用することで、コンポーネントの再レンダリングを抑止することができるのでパフォーマンス向上がする。

特に、レンダリング量が多いコンポーネントや再レンダリング頻繁に行われるコンポーネント内の子コンポーネントで有効である

React.memoの使い方

React.memoの書き方は以下のよう。

React.memo(メモ化したいコンポーネント)

以下、コードの一例

const Hoge = React.memo((props) => <div>{props.name}</div>);

codeSandbox

React.memoは、渡ってきたpropsが等価であるかをチェックして、等価であれば再レンダリングはされずにメモ化で保存したコンポーネントを再利用する。

Hogeコンポーネントは、props.nameに変更がなければコンポーネントは再レンダリングされない。

コールバック関数をpropsで渡ってきた場合は再レンダリングされる

関数に関しては再レンダリングされるたびに、新しいオブジェクトを生成するためpropsで渡ってきた場合、等価とは判断されずに再レンダリングされる。

そのため、関数の内容が同じでも再レンダリングされる。

以下がその一例

import React, { useState } from "react";

const Hoge = React.memo((props) => {
  console.log("Hoge Render!");  
  return <div onClick={props.handleClick}>{props.name}</div>
});

export const App = () => {
  const [toggle, setToggle] = useState(false);

  //  関数は再レンダリングされるたびに再生成されるため等価評価されない
  const handleClick = () => {
    console.log("Click!");
  };

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={() => setToggle(!toggle)}>
        Appコンポーネントを再レンダリング!
      </button>
      <br />
      <Hoge name={"fuga"} handleClick={handleClick} />
    </div>
  );
};

codeSandbox

この問題を解消するためには、useCallbackを使用するとよい。

useCallback

先述にあるようにReact.memoでメモ化したコンポーネントにコールバック関数が渡ってきた場合は再レンダリングがされる。

そのため、useCallbackを併用する。

useCallbackはメモ化したコールバック関数を返すhookである。

まず、useCallbackでコールバック関数メモ化する。

メモ化したコールバック関数をReact.memoでメモ化したコンポーネントにpropsとして渡すと再レンダリングを抑止することができる。

useCallbackの使い方

useCallback(コールバック関数, 依存配列);

依存は配列には、コーバルバック関数が依存している要素を入れる。

依存している要素が更新されれば、関数も新たに生成される。

先程のコードのにuseCallbackを加えてみる。

import React, { useState, useCallback } from "react";

const Hoge = React.memo((props) => {
  console.log("Hoge Render!");
  return <div onClick={props.handleClick}>{props.name}</div>;
});

export const App = () => {
  const [toggle, setToggle] = useState(false);

  // 関数をメモ化。等価ななるためHogeコンポーネントは再レンダリングされない
  const handleClick = useCallback(() => {
    console.log("Click!");
  }, []);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={() => setToggle(!toggle)}>
        Appコンポーネントを再レンダリング!
      </button>
      <br />
      <Hoge name={"fuga"} handleClick={handleClick} />
    </div>
  );
};

codeSandbox

注意点は、React.memoでメモ化していないコンポーネントへuseCallbackでメモ化したコールバックス関数を渡しても意味はなく、再レンダリングがされてしまう。

つまり、useCallbackはReact.memoと併用して使用するものだということ。

また、useCallbackでメモ化したコールバック関数を、自身のコンポーネントで利用しても動作はするが意味がない。

useMemo

useMemoは計算結果の値をメモ化して返すhook。

useMemoの使い方

useMemo(() => 計算結果を出すロジック, 依存配列);

useMemoは、値が変わらない場合、再計算をさせないことでパフォーマンスを向上することができる。

依存配列には、値を計算する際に依存している要素を入れて、更新された時だけ再計算がされる。

また、React.memoのようにレンダリングもメモ化できる。

以下のコードは2倍にする計算をメモ化している。

Appコンポーネントが再レンダリングされても、doubleが実行されないことが分かる。

import React, { useState, useMemo } from "react";

export const App = () => {
  const [toggle, setToggle] = useState(false);

  const double = (count) => {
    console.log("Run double!");
    return count * 2;
  };

 // 2倍する計算結果をメモすることで、再レンダリングされても再計算されない
  const doubleResult = useMemo(() => double(1), []);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={() => setToggle(!toggle)}>
        Appコンポーネントを再レンダリング!
      </button>
      <div>{doubleResult}</div>
    </div>
  );
};

codeSandbox

レンダリングのメモ化

useMemoはレンダリングもメモ化できる。

以下は、Hogeコンポーネントのレンダリングをメモ化して、不要なレンダリングを抑止している。

注意点として、関数コンポーネント内で、コンポーネントをメモ化したい時にuseMemoでメモ化ができるが、React.memoのようにコンポーネント外でではできない。

逆にコンポーネント内でReact.memoを利用しても意味がない。

import React, { useState, useMemo } from "react";

export const App = () => {
  const [toggle, setToggle] = useState(false);

  const Hoge = useMemo(() => {
    console.log("Hoge Render!");
    return <div>fuga</div>;
  }, []);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={() => setToggle(!toggle)}>
        Appコンポーネントを再レンダリング!
      </button>
      <br />
      {Hoge}
    </div>
  );
};

codeSandbox

メモ化をする処理自体のコストについて

useMemoやuseCallbackを使用してメモ化することで、パフォーマンスの向上を見込めるが、何でもかんでもメモ化したらいいわけではない。

なぜなら、メモ化する処理自体にもコストがかかるから。

useCallbackのメモ化のコストは、関数を再生成するコストより大きくなってしまう場合が多いから。

なので、useCallbackをわざわざ利用する必要ないところで使用するとパフォーマンスが悪くなってしまうということ。

明らかに再レンダリングや再計算のコストが高い場合に使用して、適切に使用することがポイントとなる。

The post 【初心者解説】React.memo, useMemo, useCallbackとは? first appeared on POPWEB.]]>
https://blog.popweb.dev/programming/react/%e3%80%90%e5%88%9d%e5%bf%83%e8%80%85%e8%a7%a3%e8%aa%ac%e3%80%91react-memo-usememo-usecallback%e3%81%a8%e3%81%af%ef%bc%9f/feed/ 0
【JavaScript】プリミティブ型(基本型)とオブジェクト型(参照型)について https://blog.popweb.dev/programming/javascript/primitive-object/ https://blog.popweb.dev/programming/javascript/primitive-object/#respond Sat, 16 Oct 2021 08:14:10 +0000 https://blog.pop-web.net/?p=1020 JavaScriptにのデータ型には、プリミティブ型(基本型)とオブジェクト型(参照型)がある プリミティブ型(基本型) オブジェクト型(参照型) プリミティブ型(基本型)以外のデータ型 プリミティブ型とオブジェクト型の […]

The post 【JavaScript】プリミティブ型(基本型)とオブジェクト型(参照型)について first appeared on POPWEB.]]>
JavaScriptにのデータ型には、プリミティブ型(基本型)とオブジェクト型(参照型)がある

プリミティブ型(基本型)

真偽値(boolean)
数値(number)
文字列(string)
null
undefined
シンボル(symbol)

オブジェクト型(参照型)

プリミティブ型(基本型)以外のデータ型

オブジェクト(object)
配列(array)
関数(function)

プリミティブ型とオブジェクト型の違い

プリミティブ型は変数をコピーする時、変数の中身の値がそのままコピーされる。

オブジェクト型は変数をコピーする時、その値がコピーされるのではなく、そのオブジェクトが持っているメモリ上のアドレスがコピーされる。

以下がその例

プリミティブ型の場合

let a = 20;
let b = a;
a = 80;
console.log(a); // 80
console.log(b); // 20

bにaを代入した後にaに新たに100の値を代入しているが、bに影響は受けない。

さっきも説明したように、メモリ参照せずに変数の値をそのままコピーしていることが分かる。

オブジェクト型の場合

let obj1 = {
  name: "ken",
  age: 20
};
let obj2 = obj1;
obj1.age = 80;
console.log(obj1.age); // 100
console.log(obj2.age); // 100

obj2にobj1を代入することで、obj1もobj2も同じメモリ上のアドレスと保持するようになったため、片方のageの値を変更すると、もう片方の値も同じになる。

The post 【JavaScript】プリミティブ型(基本型)とオブジェクト型(参照型)について first appeared on POPWEB.]]>
https://blog.popweb.dev/programming/javascript/primitive-object/feed/ 0
eslintのルールで特定ファイルのみ適用外にしたい場合の書き方 https://blog.popweb.dev/programming/javascript/eslint-overrides/ https://blog.popweb.dev/programming/javascript/eslint-overrides/#respond Fri, 28 May 2021 08:14:55 +0000 https://blog.popweb.dev/?p=1697 .eslintrcのrulesに「defalut export」の記述を禁止するルールを追加したとする。 このとき、sotrybookのstories.tsxにはこのルールは適用外にしたい。 その場合にはどうするか? o […]

The post eslintのルールで特定ファイルのみ適用外にしたい場合の書き方 first appeared on POPWEB.]]>
.eslintrcのrulesに「defalut export」の記述を禁止するルールを追加したとする。

module.exports = {
...
  rules: {
...
    "import/no-default-export": "error",
...
  }
};

このとき、sotrybookのstories.tsxにはこのルールは適用外にしたい。

その場合にはどうするか?

overridesを使って、適用したいファイル名とルールを無効化する記述すればよい。

module.exports = {
...
  rules: {
...
    "import/no-default-export": "error",
...
  },
  overrides: [
    {
      files: ["**/*.stories.tsx"],
      rules: {
        "import/no-default-export": "off",
      },
    },
  ],
};

参考文献

Configuration Files - ESLint - Pluggable JavaScript Linter
A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code qua...
The post eslintのルールで特定ファイルのみ適用外にしたい場合の書き方 first appeared on POPWEB.]]>
https://blog.popweb.dev/programming/javascript/eslint-overrides/feed/ 0
【Laravel】中間テーブルのカラムに対して検索をかけたい時【whereHas】 https://blog.popweb.dev/programming/laravel/%e3%80%90laravel%e3%80%91%e4%b8%ad%e9%96%93%e3%83%86%e3%83%bc%e3%83%96%e3%83%ab%e3%81%ae%e3%82%ab%e3%83%a9%e3%83%a0%e3%81%ab%e5%af%be%e3%81%97%e3%81%a6%e6%a4%9c%e7%b4%a2%e3%82%92%e3%81%8b%e3%81%91/ https://blog.popweb.dev/programming/laravel/%e3%80%90laravel%e3%80%91%e4%b8%ad%e9%96%93%e3%83%86%e3%83%bc%e3%83%96%e3%83%ab%e3%81%ae%e3%82%ab%e3%83%a9%e3%83%a0%e3%81%ab%e5%af%be%e3%81%97%e3%81%a6%e6%a4%9c%e7%b4%a2%e3%82%92%e3%81%8b%e3%81%91/#respond Wed, 17 Mar 2021 01:10:12 +0000 https://blog.popweb.dev/?p=1677 タイトル通りだが、まずはやりたいことの説明 やりたいこと リレーション先の中間テーブルのカラムの値に対して検索をかけたい。 状況 menus、stores、menu_store(中間テーブル)とうテーブルを作成しており、 […]

The post 【Laravel】中間テーブルのカラムに対して検索をかけたい時【whereHas】 first appeared on POPWEB.]]>
タイトル通りだが、まずはやりたいことの説明

やりたいこと

リレーション先の中間テーブルのカラムの値に対して検索をかけたい。

状況

menus、stores、menu_store(中間テーブル)とうテーブルを作成しており、

モデルは以下のような感じで中間テーブルを置いてリレーションしている。

class Menu extends Model
{    
    public function stores()
    {
      return $this->belongsToMany('App\Store','menu_store','menu_id','store_id')->withTimestamps();
    }
}
class Store extends Model
{    
    public function menus()
    {
      return $this->belongsToMany('App\Menu');
    }
}

解決方法

whereHasを使う。

以下だと、中間テーブルであるmenu_storeのstore_idでwhereInで条件を絞りたい時の場合。

$storeId = [1,2,3]
$query = Menu::query();
$query->whereHas('stores', function($q) use($storeId)  {
    $q->whereIn('menu_store.store_id', $storeId);
});

コールバック関数の中でリレーション先である中間テーブルの検索条件を指定してあげれば良い。

中間テーブルのカラムではなく、中間テーブルを介して結合しているテーブル(storesテーブル)のカラムで検索することも可能。

その場合も同様でコールバック関数の中の詳細条件を変更すれば良い。

$q->whereIn('store.store_id', $storeId)

The post 【Laravel】中間テーブルのカラムに対して検索をかけたい時【whereHas】 first appeared on POPWEB.]]>
https://blog.popweb.dev/programming/laravel/%e3%80%90laravel%e3%80%91%e4%b8%ad%e9%96%93%e3%83%86%e3%83%bc%e3%83%96%e3%83%ab%e3%81%ae%e3%82%ab%e3%83%a9%e3%83%a0%e3%81%ab%e5%af%be%e3%81%97%e3%81%a6%e6%a4%9c%e7%b4%a2%e3%82%92%e3%81%8b%e3%81%91/feed/ 0
【JavaScript入門】reduceについて説明と使い方 https://blog.popweb.dev/programming/javascript/javascript-reduce/ https://blog.popweb.dev/programming/javascript/javascript-reduce/#respond Tue, 26 Jan 2021 09:06:52 +0000 https://blog.popweb.dev/?p=1476 reduce()の説明と使い方を説明する。 reduce()は、配列の隣り合う値に対して関数を適用させて、その実行結果を返すメソッド。 コードを書いて動きを確認してみる。 まず、第2引数のcurには、arrの値が順番に入 […]

The post 【JavaScript入門】reduceについて説明と使い方 first appeared on POPWEB.]]>
reduce()の説明と使い方を説明する。

reduce()は、配列の隣り合う値に対して関数を適用させて、その実行結果を返すメソッド。

コードを書いて動きを確認してみる。

const arr = [1, 2, 3]

console.log(arr.reduce((acc, cur) => acc + cur)) // 6

まず、第2引数のcurには、arrの値が順番に入ってくる。

第1引数accには前回実行時の値が入ってくる。

そして、返値として最後に実行された値を返す。

具体的に実行処理は以下。

  • 1回目の実行:cur=1となり、前回実行の値はないので、1が返る
  • 2回目の実行:cur=2となり、前回実行の値はacc=1なので、1+2=3が返る
  • 3回目の実行:cur=3となり、前回実行の値はacc=1なので、3+3=6が返る
The post 【JavaScript入門】reduceについて説明と使い方 first appeared on POPWEB.]]>
https://blog.popweb.dev/programming/javascript/javascript-reduce/feed/ 0
LaravelでスクレイピングしてHerokuで定期実行する方法 https://blog.popweb.dev/programming/laravel/laravel%e3%81%a7%e3%82%b9%e3%82%af%e3%83%ac%e3%82%a4%e3%83%94%e3%83%b3%e3%82%b0%e3%81%99%e3%82%8b%e6%96%b9%e6%b3%95/ https://blog.popweb.dev/programming/laravel/laravel%e3%81%a7%e3%82%b9%e3%82%af%e3%83%ac%e3%82%a4%e3%83%94%e3%83%b3%e3%82%b0%e3%81%99%e3%82%8b%e6%96%b9%e6%b3%95/#respond Fri, 22 Jan 2021 04:38:07 +0000 https://blog.popweb.dev/?p=1472 まず、LaravelでWebスクレイピングするため、ライブラリである「FriendsOfPHP/Goutte」をインストールする。 LaravelのバージョンはLaravel6.20。 インストール 以前のLaravel […]

The post LaravelでスクレイピングしてHerokuで定期実行する方法 first appeared on POPWEB.]]>
まず、LaravelでWebスクレイピングするため、ライブラリである「FriendsOfPHP/Goutte」をインストールする。

LaravelのバージョンはLaravel6.20。

インストール

$ composer require fabpot/goutte

以前のLaravelのバージョンではconfigファイルを設定する必要があるが、Laravel5.5以降はAutoDiscoveryがあるのでそのまま使える。

実装

まず、controllerを作成する。

$ php artisan make:controller ScrapingController

controllerに処理を書く

今回は漫画書籍ランキングからタイトルだけ取得してみる。

<?php

namespace App\Http\Controllers;

use Goutte\Client;

class ScrapingController extends Controller
{
    public function scraping()
    {
        $client = new Client();
        $crawler = $client->request('GET', 'https://www.amazon.co.jp/gp/bestsellers/digital-text/2430812051/ref=pd_zg_hrsr_digital-text');
        $titles = $crawler->filter('li.zg-item-immersion')->each(function ($li) {
            $title = $li->filter('div.p13n-sc-truncate-desktop-type2')->text();
            return $title;
        });
        return view('scraping', compact('titles'));
    }
}

基本的には、use Goutte\Client;してnew Client();でインスタンスを作ると色々メソッドが使えるようになる。

使い方は、FriendsOfPHP/GoutteDomCrawlerが参考になると思う。

viewを作る

次に取得したタイトルを表示するviewをつくる。

@extends('layouts.app')

@section('content')
    <ol class="container">
        @foreach($titles as $title)
            <li>{{ $title }}</li>
        @endforeach
    </ol>
@endsection

ルーティングの設定

Route::get('/scraping', 'ScrapingController@scraping')->name('scraping');

表示の確認

ブラウザで表示確認してみる。

定期実行のやり方

定期実行されるには、まずコマンドラインで実行させるためコマンドクラスを作成する。

$ php artisan make:command ScrapingCommand

コマンドクラスに処理を書く

app/Console/Commands/ScrapeCommand.phpが作成されているので、これを編集。

<?php

namespace App\Console\Commands;

// useでGoutte\Clientをインポート
use Goutte\Client;
use Illuminate\Console\Command;

class ScrapingCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    // コマンド名を変更
    protected $signature = 'command:ScrapingCommand';

    /**
     * The console command description.
     *
     * @var string
     */
    // コマンドの説明を変更
    protected $description = 'スクレイピングコマンド';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // スクレイピング処理を書く
        $client = new Client();
        $crawler = $client->request('GET', 'https://www.amazon.co.jp/gp/bestsellers/digital-text/2430812051/ref=pd_zg_hrsr_digital-text');
        $titles = $crawler->filter('li.zg-item-immersion')->each(function ($li) {
            $title = $li->filter('div.p13n-sc-truncate-desktop-type2')->text();
            return $title;
        });
        dd($titles);
    }
}

コマンドを実行してみる

$ php artisan command:ScrapingCommand

コマンド実行後、コマンドラインから取得が確認できたらOK。

データベース保存

データベースに保存する処理を追加。

モデルとマイグレーションファイルを作成しておく。

$ php artisan make:model Item -m

作成されたマイグレーションファイルを編集

<?php

//...

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title');
            $table->timestamps();
        });
    }

    //...
}

マイグレーションを実行しておく。

$ php artisan migrate

データベース保存

コマンドクラスにデータベース保存処理を追記。

<?php

namespace App\Console\Commands;

use App\Item;
use Goutte\Client;
use Illuminate\Console\Command;

class ScrapingCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    // コマンド名
    protected $signature = 'command:ScrapingCommand';

    /**
     * The console command description.
     *
     * @var string
     */
    // コマンドの説明
    protected $description = 'スクレイピングコマンド';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // スクレイピング処理を書く
        $client = new Client();
        $crawler = $client->request('GET', 'https://www.amazon.co.jp/gp/bestsellers/digital-text/2430812051/ref=pd_zg_hrsr_digital-text');
        $titles = $crawler->filter('li.zg-item-immersion')->each(function ($li) {
            $title = $li->filter('div.p13n-sc-truncate-desktop-type2')->text();
            return $title;
        });
        //データベース保存
        foreach ($titles as $title)
        {
            $item = new Item;
            $item->title = $title;
            $item->save();
        }
    }
}

Herokuに定期実行を設定

Herokuにアプリをデプロイしておく。

次に、HerokuSchedulerアドオンをアプリに追加。

$ heroku addons:create scheduler:standard

HerokuSchedulerのダッシュボードを開く。

$ heroku addons:open scheduler

Add Jobをクリックして、ジョブを登録する。

「Schedule」で実行時刻を選択し、「Run Command」に作成したコマンドクラスを実行するコマンドを入力しておく。

これで、定期的にスクレイピングしてデータを取得できるようになる。

The post LaravelでスクレイピングしてHerokuで定期実行する方法 first appeared on POPWEB.]]>
https://blog.popweb.dev/programming/laravel/laravel%e3%81%a7%e3%82%b9%e3%82%af%e3%83%ac%e3%82%a4%e3%83%94%e3%83%b3%e3%82%b0%e3%81%99%e3%82%8b%e6%96%b9%e6%b3%95/feed/ 0
テキスト下に蛍光色ラインマーカーをCSSで作る(改行対応) https://blog.popweb.dev/programming/css/css-line-marker/ https://blog.popweb.dev/programming/css/css-line-marker/#respond Thu, 31 Dec 2020 22:56:58 +0000 https://blog.popweb.dev/?p=1568 改行されているテキストにも対応できるCSSによるラインマーカーの作成。 以下、コード。 HTML CSS

The post テキスト下に蛍光色ラインマーカーをCSSで作る(改行対応) first appeared on POPWEB.]]>
改行されているテキストにも対応できるCSSによるラインマーカーの作成。

以下、コード。

HTML
<p>
  テキストテキストテキストテキストテキスト<br />
  <span class="line-marker">テキストテキストテキストテキストテキスト<br />
    テキストテキスト</span>テキストテキストテキスト<br />
  テキストテキストテキストテキストテキスト
</p>
CSS
.line-marker {
	background: linear-gradient(transparent 70%, #FDDEB3 0%);
	display: inline;
	padding: 0 2px 4px;
}
The post テキスト下に蛍光色ラインマーカーをCSSで作る(改行対応) first appeared on POPWEB.]]>
https://blog.popweb.dev/programming/css/css-line-marker/feed/ 0
ngrokでDockerのローカル開発環境を簡単にWEB公開する方法 https://blog.popweb.dev/server/ngrok-docker/ https://blog.popweb.dev/server/ngrok-docker/#respond Fri, 18 Dec 2020 07:48:53 +0000 https://blog.popweb.dev/?p=1543 ローカル開発環境の状況をクライアントへ確認してもらいたい時、もしくは複数端末でブラウザ確認したい時は多々ある。 しかし、ちょっと確認してもらえればいいのに、いちいちテスト環境用のサーバを用意してにアップロードするのは面倒 […]

The post ngrokでDockerのローカル開発環境を簡単にWEB公開する方法 first appeared on POPWEB.]]>
ローカル開発環境の状況をクライアントへ確認してもらいたい時、もしくは複数端末でブラウザ確認したい時は多々ある。

しかし、ちょっと確認してもらえればいいのに、いちいちテスト環境用のサーバを用意してにアップロードするのは面倒。

そこで、ローカル開発環境を簡単にWEB上に公開できるツール「ngrok」(エヌジーロック?

)を使う。

ngrokのインストール

Homebrewがインストールしているか確認。

していなければインストールしておく。

$ brew -v

以下のコマンドでngrokをインストール

$ brew install --cask ngrok
又は、
$ brew cask install ngrok

Dockerのローカル開発環境をWEB公開する

Dockerのローカル開発環境をWEB公開するには、まずはポートを確認。

以下のようなURLで開発環境を確認している場合

http://localhost:10080/

以下の、コマンドでngrokが起動する

$ ngrok http 10080

起動すると公開用のURLが発行される。

Forwardingのhttp://〜にアクセスすれば、WEB公開できたことが確認できる。

公開を止める時は、Ctrl + C

The post ngrokでDockerのローカル開発環境を簡単にWEB公開する方法 first appeared on POPWEB.]]>
https://blog.popweb.dev/server/ngrok-docker/feed/ 0