初心者SEのつぶやき

初心者SEのつぶやき

Pythonを用いたWebスクレイピングの方法

やりたいこと

Pythonで動的に生成されているサイトをスクレイピングしたい。
(Pythonのバージョンは3.11.7を利用している)

方法

seleniumとwebdriver-managerを利用する。

インストール

  • 下記コマンドでseleniumをインストールする。
 pip install selenium
  • 下記コマンドでwebdriver-managerをインストールする。
pip install webdriver-manager

実装例

  • 必要なライブラリをimport
  # import libraries
  import os
  from selenium import webdriver
  from selenium.webdriver.chrome.service import Service
  from selenium.webdriver.common.by import By
  from webdriver_manager.chrome import ChromeDriverManager
  from selenium.webdriver.support.ui import WebDriverWait
  from selenium.webdriver.support import expected_conditions as EC
  driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
  • ページをロード
  driver.get(対象のURL)
  # ロード待ちを10秒に指定
  driver.implicitly_wait(10)
  driver.quit()

要素の取得&利用法(一部)

  • クラス名指定で要素取得
  # find_elementsメソッドで、input-formクラス要素を全て取得
  class_contents = driver.find_elements(By.CLASS_NAME, "input-form")
  
  #find_elementメソッドで、custom-buttonクラスのうち初めの一つ取得
  button = driver.find_element(By.CLASS_NAME, "custom-button")
  • XATH指定で要素を取得
listbox = self.driver.find_element(By.XPATH, '//ul[@role="listbox"]')
  • タグ名指定で要素を取得
# liタグを取得
list_items = listbox.find_element(By.TAG_NAME, 'li')
  • ID名指定で要素を取得
tab_content = self.driver.find_element(By.ID, "abc")
  • input要素を入力
input_content.clear()
input_content.send_keys(入力したい内容)
  • ボタン押下処理
wait = WebDriverWait(driver, 10)
button.click()
wait.until(EC.staleness_of(button))
  • スクショを撮る
  driver.save_screenshot(保存先)

感想

スクレイピングはできるようになったが、やはり実行時間が長いので
高速化手段がないか検討したい&将来バッチ実行をさせてみたい。

今回の内容が参考になったら幸いです。

【Ruby on Rails】devise導入方法

やりたいこと

railsアプリケーションにて、deviseを用いた認証機能を導入したい。

導入方法

インストール

  • Gemfileにdeviseを追加し、bundle installを実行する。
 gem 'devise'
  • 下記コマンドでdeviseをインストールする。
rails g devise:install

モデル作成

  • 下記コマンドでモデルを作成する。
rails g devise User
  • 実行後、下記ファイルが作成されているか確認
    (その他テストファイルなども作成されている)

    • app/models/user.rb
    • db/migrate/XXXXXXXXXXXXXX_devise_create_user
  • migrationを実行

rails db:migrate

ページ作成

  • 下記コマンドでコントローラーを作成する
rails g controller homes top
  • ルーティングの作成(config/routes.rb)
Rails.application.routes.draw do
  devise_for :users
  root: 'homes#top'
end

動作確認

railsサーバーを起動後、下記URLにアクセスできたら完了

  • localhost:3000/users/sign_up → サインアップページ
  • localhost:3000/users/sign_in → サインインページ

補足

  • viewの編集を行いたい場合config/initializers/devise.rbを修正する。
config.scoped_views = true

感想

deviseのカスタマイズは結構奥が深そうなので、別の機会にまとめたい。

今回の内容が参考になったら幸いです。

ReactでAWS lambdaからレスポンスを受け取る方法

やりたいこと

AWS lambdaで実行した結果がバイナリーデータでしか受け取れず、
戻り値が活用できない。

戻り値を活用できるようにバイナリーデータを変換したい。

実現方法

TextDecoderを利用してASCII形式に変換をする。

実装方法は下記となる。
(lambda実装はReactを使ってAWS lambdaを実行する方法 - 初心者SEのつぶやき の記載参考)

    // lambdaの実行
    const lambdaResponse = await lambda.send(lambdaCommand);
    //「Uint8Array(57) [34, 123, 92, 110, 32, 30.....」のようなデータが出力される。
    console.log("Lambda response:", lambdaResponse.Payload);

    // asciiに変換処理
    const asciiDecoder = new TextDecoder('ascii');
    const data = asciiDecoder.decode(lambdaResponse.Payload);
    console.log("Lambda response body:", data);

lambda側での実装は下記となる。

import json

def lambda_handler(event, context):
  params = {
        'statusCode':200,
        'body': 'success!!'
      }
  resp = json.dumps(params, ensure_ascii=False, indent=2)
  return resp

実行後、下記が出力された。

Lambda response body: "{\n  \"statusCode\": 200,\n  \"body\": \"success!!\"\n}"

感想

lambdaからのレスポンスが受け取れなくて頭を悩ませていたので、
解決ができて安堵している。

今回の内容が参考になったら幸いです。

create-react-appを使わずにReactの環境構築を行う方法

やりたいこと

Reactアプリに追加でライブラリをインストールしようとしたら
依存関係の沼にハマったので、create-react-appコマンドを使わずに
Reactの環境構築を行いたい。

実現方法

webpackを用いて環境構築を行う。
webpackは複数のJavaScriptファイルを一つのファイルにまとめて出力するツールである。

プロジェクトの初期化

下記コマンドを実行して初期化&package.jsonを生成する。

npm init -y

webpackのインストール

下記3種をインストールを行う。

  • webpack

  • webpack-cli

  • webpack-dev-server

npm install -D webpack webpack-cli webpack-dev-server

webpackの動作確認

lodashを用いて、動作確認を行う

npm install lodash

./src./distに動作確認用のファイルを作成する。

./src/index.jsに下記を記述する。

import _ from 'lodash';

  function sample() {
    const element = document.createElement('div');
    element.innerHTML = _.join(['webpack','動作確認'], ' ');
    return element;
  }

  document.body.appendChild(sample());

./dist/index.htmlは下記を記述する。

 <!DOCTYPE html>
  <html>
    <head>
      <meta charset="utf-8" />
      <title>sample</title>
    </head>
    <body>
      <script src="main.js"></script>
    </body>
  </html>

下記コマンドを実行してlocalhost:8080に接続し、動作確認ページが表示できたら
正しくインストールされている。

npx webpack server --open --static-directory dist --mode=development

webpackの設定

下記コマンドを実行し、対話形式でwebpackの初期設定を行う。

npx webpack-cli init

今回は下記選択を行なった。(プロジェクトによって選択が変わります。)

  • Which of the following JS solutions do you want to use? (Use arrow keys):Typescript
  • Do you want to use webpack-dev-server? (Y/n) :Y

  • Do you want to simplify the creation of HTML files for your bundle? (Y/n) :Y

  • Do you want to add PWA support? (Y/n) :N
  • Which of the following CSS solutions do you want to use? (Use arrow keys):SASS
  • Will you be using CSS styles along with SASS in your project? (Y/n) :Y
  • Will you be using PostCSS in your project? (y/N):N
  • Do you want to extract CSS for every file? (Use arrow keys):Y
  • Do you like to install prettier to format generated configuration? (Y/n) :Y
  • Pick a package manager: (Use arrow keys):npm
  • Overwrite package.json? (ynarxdeiH) :Y

webpack設定ファイルの変更

下記内容にwebpack.config.jsを置き換える

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const isProduction = process.env.NODE_ENV === 'production';

const stylesHandler = MiniCssExtractPlugin.loader;

module.exports = {
    entry: './src/index.tsx',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/',
    },
    devServer: {
        open: true,
        host: 'localhost',
        historyApiFallback: true, // Reactのルーティングを扱うために追加
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: 'index.html',
        }),
        new MiniCssExtractPlugin(),
    ],
    module: {
        rules: [
            {
                test: /\.(ts|tsx)$/i,
                loader: 'ts-loader',
                exclude: /node_modules/,
            },
            {
                test: /\.css$/i,
                use: [stylesHandler, 'css-loader'],
            },
            {
                test: /\.s[ac]ss$/i,
                use: [stylesHandler, 'css-loader', 'sass-loader'],
            },
            {
                test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
                type: 'asset',
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.jsx', '.js'],
    },
    mode: isProduction ? 'production' : 'development',
};

Reactのインストール

下記コマンドでreactのインストールを行う。

npm install react react-dom

TypeScriptのインストール

下記コマンドでTypescriptをインストールする。

npm install -D typescript

tsconfig.jsonを削除した後、下記コマンドを実行する。

npx tsc --init

下記コマンドで、reactとreact-domの型定義のインストールを行う。

npm install --save @types/react @types/react-dom

tsconfig.jsonに下記設定を加える。

"compilerOptions": {
  "jsx": "react"
}

動作確認

動作確認前準備

./index.htmlを編集する。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
</body>

</html>

./src/index.tsxを作成する。

import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

const container = document.getElementById('app');
const root = createRoot(container!);

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

./src/App.tsxを作成する。

import React from 'react';

function App() {
  return(
    <div>
      Hello React!!
    </div>
  )
}

export default App;

package.jsonに下記コマンドを加える。

"scripts": {
    "start": "webpack-dev-server --mode development"
}

実行

下記コマンドを実行後、localhost:8080にHello Reactの文言が出力されれば成功となる。

npm start

感想

create-react-appで後から色々なライブラリをインストールすると、依存関係でハマっていたが、0から構築することでカスタマイズしやすくなった。
次のステップとして、eslintやPrettierの設定をまとめられたらと考えている。

今回の内容が参考になったら幸いです。

AWS LambdaでS3のデータを扱う方法

やりたいこと

AWS S3に格納されているデータをlambdaで扱いたい。
具体的にはs3のファイルをダウンロードし、lambdaで編集を行なった後
s3に再度アップロードさせたい。

言語はPythonを用いて実装したい。

実現方法

boto3を用いて実装を行う。
downloadメソッドに対して、「バケット名」「s3のファイル名」「lambdaの保存先(tmp直下)」を指定する。

uploadメソッドに対して、「アップロードしたいファイル名(lambda)」「バケット名」「アップロード先(s3)のファイル名」を指定する。

実装例は下記となる。

S3ファイル取得処理

import json
import boto3

def lambda_handler(event, context):
    # botoインスタンス生成
    s3 = boto3.client('s3')
   
    bucket_name = 'S3のバケット名を選択'
    tmp_file = '/tmp/' + event['fileName']

    try:
      # s3の対象バケットからlambda内のtmp直下にファイルをダウンロードする。
      s3.download_file(bucket_name, event['fileName'], tmp_file)

      # ファイルに対する処理を記載する。

      # s3の対象バケットに対して、lambda内のtmp直下にファイルをアップロードする。
      s3.upload_file(tmp_file, bucket_name, event['fileName'])

      return return{
        'statusCode':200,
        'body': 'success'
      }
    except Exception as e:
      return{
        'statusCode':500,
        'body': f'{str(e)}'
      }

感想

今回は実装というより、AWSの権限周りで時間がかかった印象だったため、 IAMサービスの権限周りの使い方をまとめたいと思った。
今回は実装までということで...

今回の内容が参考になったら幸いです。

Reactを使ってAWS lambdaを実行する方法

やりたいこと

Reactを使ってAWS lambdaを実行したい。
開発環境はReact 18.12.0、 Typescript4.9.5

実現方法

aws-sdkを用いて実装を行う。 aws-sdknpm install aws-sdkでインストールする。
client-lambdaをnpm install @aws-sdk/client-lambdaでインストールする。

LambdaClientにregioncredentialsを設定する。

lambdaパラメータにFunctionName,Payloadを指定する。 (今回の実行に必要な分だけ指定している。)

上記内容を基にlambda実行リクエスト処理を実装した。(環境変数は別途指定) 作成したのはファイル名と拡張子をリクエストとして飛ばす処理である。

lambda実行リクエスト処理

// lambda関係をimort
import { LambdaClient, InvokeCommand } from "@aws-sdk/client-lambda";
// LambdaClientの設定
const lambda = new LambdaClient({
  region: AWS_REGION, 
  credentials: {
    accessKeyId: AWS_KEY,
    secretAccessKey: AWS_SEACRET_KEY
  },
});


export const lambdaExe = async (fileName:string ,extention: string): Promise<boolean> => {
  // パラメータ指定(PayloadはJSON形式)
  const lambdaParams = {
    FunctionName: AWS_FUNCTION,
    Payload: JSON.stringify({"extention":extention, "fileName":fileName})
    
  };
  try {
    // invokeコマンドのインスタンス生成
    const lambdaCommand = new InvokeCommand(lambdaParams);
    // コマンド実行
    const lambdaResponse = await lambda.send(lambdaCommand);
    console.log("Lambda response:", lambdaResponse);
    // 今回は簡易的に200が返却された時Trueをreturnしている。
    return lambdaResponse.StatusCode === 200;
  } catch (error) {
    console.error("Error:", error);
    return false;
  }
}

lambda側の実装(Pythonで記載)

import json

def lambda_handler(event, context):
      return {
        'statusCode':200
      }

感想

lambdaは結構ドキュメントが豊富で親切なイメージだった。
(英語に抵抗感なければ)
下記を参考にして作成した。 docs.aws.amazon.com

今回の内容が参考になったら幸いです。

Reactを使ってAWS S3からファイルURLを取得する方法

やりたいこと

Reactを使ってAWS S3からファイルURLを取得したい。
開発環境はReact 18.12.0、 Typescript4.9.5

実現方法

aws-sdkを用いて実装を行う。 aws-sdknpm install aws-sdkでインストールする。

S3インスタンスAWS_KEYAWS_SEACRET_KEYを設定する。

getSignedUrlメソッドの第一引数にgetObjectを第二引数にバケットとファイルを指定する。

上記内容を基にダウンロードURLを実装した。(環境変数は別途指定)

// aws-sdkのインポート
import AWS from "aws-sdk";
import { Credentials } from "aws-sdk";

export const s3Url = async (fileName:String, extention: string): Promise<string | undefined> => {
  // 認証情報設定
  const creds = new Credentials(
    AWS_KEY,
    AWS_SEACRET_KEY
  );
  // s3インスタンス生成
  const s3 = new AWS.S3({ region: AWS_REGION, credentials: creds });
  // output配下のファイルを指定
  const filePath = "output/" + fileName;
  // バケット名とファイルを指定
  const getUrlParams = {
    Bucket: AWS_BUCKET,
    Key: filePath,
  }
  try {
    // 取得処理を実行
    const downloadUrl = await s3.getSignedUrl("getObject",getUrlParams);
    return downloadUrl;
  } catch (error) {
    console.error("Error generating signed URL:", error);
    return undefined;
  }
}

感想

今回取得したURLからプレビュー表示をさせたり、ダウンロードリンクを生成させたりできるので、 実装サンプルあげていきたい。 AWSから直接ファイルをダウンロードできると、やれることも広がりそう。

今回の内容が参考になったら幸いです。