技術雑記帳兼日記帳

AWS、Python、AIの使い方をコッソリ

WSLでssh

ssh自動起動しないので、いつもどおりsystemctlコマンド打ってもだめだった。
qiita.com 上記のリンクのコマンドラインで起動したらうまくいった。 ただ、自分の環境だとバッチファイルが起動できない。
色々ググったけどだめだから、スタートアップにショートカット作成でコマンド投入したらうまく行った。

Mac買いどきかなぁ

python WSL

やんごとなき事情でWindowsPython環境を作ったが、なれないのでWSLのUbuntuで実行環境を作った。
そのときに、turtleが表示されなかったのでメモ

以下をWindowsにインストール

sourceforge.net


Linux側で下記を設定

$ export DISPLAY=localhost:0.0

あとはturtleを使ったプログラムを動かして表示されればOK

WSL2だと「localhost」の箇所をWindowsIPアドレスにしないとだめみたい。
WSLは逆にIPを設定すると動かなかった。

Amazon S3 and boto3

忘れそうなのでメモついでにAWS CLIPythonでS3の使い方をまとめる。

docs.aws.amazon.com

S3の設定

aws s3 mb s3://バケット名
aws s3 sync images s3://バケット名/images/
aws s3 rm  s3://バケット名/ --include 'img*.jpg' --recursive --dryrun
でためして
aws s3 rm  s3://バケット名/ --include 'img*.jpg' --recursive
aws s3 ls s3://バケット名/images/

バケットを作るときに以下のNGが出た場合はAWS内で重複しているのでバケット名を替える必要がある

make_bucket failed: s3://imagebucket An error occurred (BucketAlreadyExists) when calling the CreateBucket operation: The requested bucket name is not available. The bucket namespace is shared by all users of the system. Please select a different name and try again.

「/」のつけ忘れでフォルダ、ファイルが混同するので注意が必要

最後にpythonでimg-catの中身をS3に転送して結果をCSVに出力するプログラムを書いてみた。

import boto3, pathlib 

s3 = boto3.client('s3')

files = pathlib.Path('img-cat/').glob('*.jpg')
for file in files:
    s3.upload_file('img-cat/'+ file.name, 'バケット名', 'img-cat/' + file.name)

objs = s3.list_objects_v2(Bucket='バケット名')
csv = '{},{}\n'.format('file', 'size')

for o in objs.get('Contents'):
    key = o.get('Key')
    size = o.get('Size')
    if key[-4:]=='.jpg':
        csv += '{},{}\n'.format(key, int(size))

f = open('uplist.csv', 'w')
f.write(csv)

AWS CLIとboto3を使いこなして幸せになりたいな。

python スクレイピング その7

はじめに

今回はScrapyを使用してNPBの種類ごとの歴代最高記録のURLを取得してみた。

準備

Scrapyのインストール

$ pip install scrapy

Scrapyプロジェクトの作成

$ scrapy startproject npb
$ cd npb
$ tree
.
├── npb
│   ├── __init__.py
│   ├── items.py
│   ├── middlewares.py
│   ├── pipelines.py
│   ├── settings.py
│   └── spiders
│       └── __init__.py
└── scrapy.cfg

2 directories, 7 files

設定は「settings.py」にまとまっている模様。

item.pyに「url = scrapy.Field()」を追加する。

  • items.py
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class NpbItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    url = scrapy.Field()
    pass
# -*- coding: utf-8 -*-
import scrapy

class NpbSpiderSpider(scrapy.Spider):
    name = "npb_spider"
    allowed_domains = ["npb.jp"]
    start_urls = ["https://npb.jp/bis/history/"]

    def parse(self, response):
        for url in response.css('td.allTimeBatBmn a::attr("href")'):
            yield response.follow(url)
            
        for url in response.css('td.allTimePitBmn a::attr("href")'):
            yield response.follow(url)
        pass
  • 実行方法&結果
$ scrapy crawl npb_spider
2021-05-15 13:53:42 [scrapy.utils.log] INFO: Scrapy 2.5.0 started (bot: npb)
2021-05-15 13:53:42 [scrapy.utils.log] INFO: Versions: lxml 4.6.1.0, libxml2 2.9.10, cssselect 1.1.0, parsel 1.6.0, w3lib 1.22.0, Twisted 21.2.0, Python 3.8.5 (default, Sep  4 2020, 07:30:14) - [GCC 7.3.0], pyOpenSSL 19.1.0 (OpenSSL 1.1.1h  22 Sep 2020), cryptography 3.1.1, Platform Linux-5.8.0-45-generic-x86_64-with-glibc2.10
2021-05-15 13:53:42 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.epollreactor.EPollReactor
2021-05-15 13:53:42 [scrapy.crawler] INFO: Overridden settings:
〜〜中略〜〜
2021-05-15 13:53:43 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://npb.jp/bis/history/> (referer: None)
2021-05-15 13:53:45 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://npb.jp/bis/history/ltb_g.html> (referer: https://npb.jp/bis/history/)
2021-05-15 13:53:46 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://npb.jp/bis/history/ltp_l.html> (referer: https://npb.jp/bis/history/)
2021-05-15 13:53:48 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://npb.jp/bis/history/ltp_w.html> (referer: https://npb.jp/bis/history/)
2021-05-15 13:53:49 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://npb.jp/bis/history/ltp_nbb.html> (referer: https://npb.jp/bis/history/)
2021-05-15 13:53:50 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://npb.jp/bis/history/ltp_sho.html> (referer: https://npb.jp/bis/history/)
〜〜中略〜〜
  • 簡単な解説

下記でscrapyのプロジェクトを作成している。

$ scrapy startproject npb
$ cd npb

ここでclass名に合致したすべてのaタグのhrefを取得している。
打者成績と投手成績があるので2回取得する処理にしている。

class NpbSpiderSpider(scrapy.Spider):
    name = "npb_spider"
    allowed_domains = ["npb.jp"]
    start_urls = ["https://npb.jp/bis/history/"]

    def parse(self, response):
        for url in response.css('td.allTimeBatBmn a::attr("href")'):
            yield response.follow(url)
            
        for url in response.css('td.allTimePitBmn a::attr("href")'):
            yield response.follow(url)
        pass

まとめ

簡単かつ大規模なスクレイピングの機能が作れそう。
プロジェクト単位で管理できるので、なにかしらの素材集めをプロジェクトとして管理できそう。



python スクレイピング その6

はじめに

今回は巨人の藤田元司監督のWikiページを画像でコピーする処理を作成した。

準備

  • sele_headless.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
import time

url = 'https://ja.wikipedia.org/wiki/%E8%97%A4%E7%94%B0%E5%85%83%E5%8F%B8'

options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
driver.get(url)

width = driver.execute_script("return document.body.scrollWidth")
height = driver.execute_script("return document.body.scrollHeight")
driver.set_window_size(width, height)

time.sleep(3)
driver.save_screenshot("screenshot.png")

time.sleep(3)
driver.quit()
  • 実行方法
$ python sele_screenshot.py
  • 簡単な解説

下記で現行のChromeバージョンから最適なドライバを選択してくれる。

driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)

ここがこの処理の肝だと感じる。
スクリプト実行を意図的に行える。

width = driver.execute_script("return document.body.scrollWidth")
height = driver.execute_script("return document.body.scrollHeight")
driver.set_window_size(width, height)

まとめ

「ChromeDriverManager().install()」はパス名記載しないので、すごくスタイリッシュで格好良い。
execute_script()の応用の幅がありそう。



python スクレイピング その5

はじめに

今回は短めにヘッドレスモードを試してみる。

準備

  • sele_headless.py
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
import time

url = 'https://srad.jp/'
keyword = 'Linux'

options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options, executable_path="chromedriverのパス")
driver.get(url)

search = driver.find_element_by_name("fhfilter")
search.send_keys(keyword)
search.submit()

soup = BeautifulSoup(driver.page_source, "html.parser")
results = soup.find_all("h2", attrs={"class": "story"})

for i, result in enumerate(results):
    tag = result.find("a")
    print("%d: %s : %s" % (i + 1, tag.get_text(), "https:"+tag["href"]))

driver.quit()
  • 実行方法と結果
$ python sele_headless.py
1: Microsoft、eBPFをWindows上で利用可能にする計画 : https://opensource.srad.jp/story/21/05/11/1940206/
2: Windows 10 Insider Preview ビルド21376、WSLのLinux GUIアプリサポートで発生していた問題を解決 : https://linux.srad.jp/story/21/05/08/0455217/
3: Vine Linuxの現状は?(追記: リリース版終了が宣言される) : https://linux.srad.jp/story/21/05/04/0459248/
4: Windows 10 Insider PreviewのLinux GUIアプリ実行サポート、現時点ではHaswell世代以降のCPUが必要 : https://linux.srad.jp/story/21/04/29/0430220/
5: ミネソタ大研究者、研究のためとしてLinuxカーネルに意図的に脆弱性コードをコミット : https://linux.srad.jp/story/21/04/25/1954223/
6: M1 Mac正式対応のOS仮想化ソフト「Parallels Desktop 16.5」が公開 : https://linux.srad.jp/story/21/04/19/0129216/
7: SCO Linux FUDは滅びぬ、何度でも蘇るさ! : https://linux.srad.jp/story/21/04/04/1616223/
8: FSF運営チーム、執行役員をはじめ3名が辞任へ : https://opensource.srad.jp/story/21/04/03/0837231/
9: Linux Foundation、Linux 30周年記念ロゴ画像を公開 : https://linux.srad.jp/story/21/03/21/058252/
10: 7-Zip 20.01 alpha、Linuxに対応 : https://linux.srad.jp/story/21/03/16/1622251/
11: 火星の空飛ぶLinux : https://linux.srad.jp/story/21/03/11/1655218/
12: Linux 5.12 rc2、重大なバグ修正のため予定より数日早くリリース : https://linux.srad.jp/story/21/03/07/0039241/
13: Linus Torvalds、6日間の電源喪失を切り抜ける : https://linux.srad.jp/story/21/03/02/1653247/
14: アップデート適用が進まないLinux Mint、より多くのユーザーに迅速なアップデート適用を実行してもらうための改善計画 : https://linux.srad.jp/story/21/02/28/1940228/
  • 簡単な解説

options.add_argument('--headless')を追加することで、Chromeが画面に表示されずにスクレイピングができる。

options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options, executable_path="chromedriverのパス")

まとめ

バックグラウンドでスクレイピングできるのは便利。
GUIのないテストシステムとかで使えそう。



python スクレイピング その4

はじめに

今回はseleniumSlashdotを開いて、ブラウザを操作して結果を表示するプログラムを書いてみた。

準備

最初にpipで以下をインストールしておく。

$ pip install selenium
$ pip install chromedriver
$ pip install chromedriver-binary==90.0.4430.93

※chromedriver-binaryは自分の環境のバージョンを記載。

  • sele.py
from selenium import webdriver
from bs4 import BeautifulSoup
import time

url = 'https://srad.jp/'
keyword = 'Linux'

driver = webdriver.Chrome(executable_path="chromedriverのパス")
driver.get(url)

search = driver.find_element_by_name("fhfilter")
search.send_keys(keyword)
search.submit()

soup = BeautifulSoup(driver.page_source, "html.parser")
results = soup.find_all("h2", attrs={"class": "story"})

for i, result in enumerate(results):
    tag = result.find("a")
    print("%d: %s : %s" % (i + 1, tag.get_text(), "https:"+tag["href"]))

driver.quit()
  • 実行方法と結果
$ python sele.py 
1: Windows 10 Insider Preview ビルド21376、WSLのLinux GUIアプリサポートで発生していた問題を解決 : https://linux.srad.jp/story/21/05/08/0455217/
2: Vine Linuxの現状は?(追記: リリース版終了が宣言される) : https://linux.srad.jp/story/21/05/04/0459248/
3: Windows 10 Insider PreviewのLinux GUIアプリ実行サポート、現時点ではHaswell世代以降のCPUが必要 : https://linux.srad.jp/story/21/04/29/0430220/
4: ミネソタ大研究者、研究のためとしてLinuxカーネルに意図的に脆弱性コードをコミット : https://linux.srad.jp/story/21/04/25/1954223/
5: M1 Mac正式対応のOS仮想化ソフト「Parallels Desktop 16.5」が公開 : https://linux.srad.jp/story/21/04/19/0129216/
6: SCO Linux FUDは滅びぬ、何度でも蘇るさ! : https://linux.srad.jp/story/21/04/04/1616223/
7: FSF運営チーム、執行役員をはじめ3名が辞任へ : https://opensource.srad.jp/story/21/04/03/0837231/
8: Linux Foundation、Linux 30周年記念ロゴ画像を公開 : https://linux.srad.jp/story/21/03/21/058252/
9: 7-Zip 20.01 alpha、Linuxに対応 : https://linux.srad.jp/story/21/03/16/1622251/
10: 火星の空飛ぶLinux : https://linux.srad.jp/story/21/03/11/1655218/
11: Linux 5.12 rc2、重大なバグ修正のため予定より数日早くリリース : https://linux.srad.jp/story/21/03/07/0039241/
12: Linus Torvalds、6日間の電源喪失を切り抜ける : https://linux.srad.jp/story/21/03/02/1653247/
13: アップデート適用が進まないLinux Mint、より多くのユーザーに迅速なアップデート適用を実行してもらうための改善計画 : https://linux.srad.jp/story/21/02/28/1940228/
14: M1 Mac上でUbuntuデスクトップの起動に成功との発表。ネットワーク機能も動作可能 : https://linux.srad.jp/story/21/01/24/1511237/
  • 注意

sele.py を実行しても、Chromeのバージョンとドライバのバージョンが違うと動かない。
下記でバージョン一覧が取れるのでChromeのバージョンが90版台なら、chromedriver-binaryも同じ番号帯を選んで再インストールする。

$ pip install chromedriver-binary==
  • 簡単な解説

executable_pathは未指定でも良いらしいが自分の環境だとNGだったので指定している。

from selenium import webdriver
from bs4 import BeautifulSoup
import time

url = 'https://srad.jp/'
keyword = 'Linux'

driver = webdriver.Chrome(executable_path="chromedriverのパス")
driver.get(url)

「fhfilter」が検索ボックスでそこにsend_keys()でキーワードを送信してsubmit()している。

search = driver.find_element_by_name("fhfilter")
search.send_keys(keyword)
search.submit()

「driver.page_source」でまるっと結果を取得している。
その結果をBeautifulSoupで解析して、enumerateで回して表示している。
題名はaタグの内容をget_text()で取得し、アトリビュートのhrefを取得して表示している。

soup = BeautifulSoup(driver.page_source, "html.parser")
results = soup.find_all("h2", attrs={"class": "story"})

for i, result in enumerate(results):
    tag = result.find("a")
    print("%d: %s : %s" % (i + 1, tag.get_text(), "https:"+tag["href"]))

driver.quit()

まとめ

forの表示は最初はダラダラ3行くらい書いてたけど、今の書き方のほうがスッキリして良い。
この癖を付けていきたい。