Python 3.6 での Web スクレイピングです。
今回はファイルに吐かれたWebサイトのソースコードを抽出する方法について調べました。
【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.1】
【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.2】
【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.3】
【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(find系操作)【Part.4】
【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(URLを引数で受け取る)【Part.5】
【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(ファイルを読み込み文字列を抽出する)【Part.6】
ファイルを開く
ファイルを開くためには open 関数を使用します。
open 関数の戻り値は、指定したファイルへのポインタを持つファイルオブジェクトです。
そのオブジェクトに対して「読み込み」「書き込み」の操作をします。
【構文】
オブジェクトを格納する変数 = open(‘ファイル名’, ‘モード’)
【例】
# -*- coding: utf-8 -*- f = open(‘text.txt’, ‘r’) ← ファイルを開いています。 for line in lines: f.close() |
ファイルを読み込む
ファイルをオープンしたら、ファイルの内容を読み込みます。
以下は、カレントディレクトリ(pythonプログラムと同じディレクトリ)にある場合のファイル(text.txt)を読み込んで内容を出力する Python プログラムです。
# -*- coding: utf-8 -*- f = open(‘text.txt’, ‘r’) for line in lines: f.close() |
# -*- coding: utf-8 -*- は何か?
1行目に戻りますが、そもそも「# -*- coding: utf-8 -*-」は何でしょうか。
一言で言うと、
ソースコードを UTF-8 で記述する
ことを宣言しています。
UTF-8 は、文字コードです。
文字コードとはコンピュータがバイトの表現(00000001,00000010とか)と文字のマッピングの規則のことを言います。
例えば ASCII 文字の場合ですが「0x30」は「0」、「0x31」は「1」というようにマッピングされています。
【参考】
ASCII文字コード(IT辞典 e-Words)
http://e-words.jp/p/r-ascii.html
話を戻しますが、「# -*- coding: utf-8 -*-」は、このソースコードを「UTF-8」で記述します、と言うことを宣言しています。
その結果、以下のように日本語でコメントを追加しても文字化けをしなくなります。
(pyenv) [test@SAKURA_VPS scraping]$ vi edit_text.py
# カレントディレクトリにある「text.txt」を読み取り専用でオープンします。 for line in lines: f.close() |
ちなみに「# -*- coding: utf-8 -*-」は Python だけでなく Ruby でも使います。
マジックコメントと言うそうです。
プログラムは Ruby や PHP から勉強し始めましたが、Ruby から Python 2.X 系に移った時に文字コードの複雑さに辟易した記憶があります。
何をどうやっても文字化けしてしまう・・・
もちろんプログラムもしくは環境設定が悪いのですが、調べてもさっぱり分かりませんでした。
今は Python 3.X 系でプログラムを組んでいますが、Python イコール文字化けが恐ろしいというイメージがまだまだ残っています。
ファイルの読み込み方は数種類ある
Pythonでファイルを読み込む方法は数種類あります。
まとめると
- read ← ファイルの内容をまるっと読み込み(1行毎ではなく、全部まるっと読み込み)、全体を1つの文字列として返す
- readline ← 1行ずつ読み込み文字列として返す
- readlines ← ファイルの内容をまるっと読み込み、リストを返す
の3つになります。
(pyenv) [test@SAKURA_VPS scraping]$ vi edit_text.py # カレントディレクトリにある「text.txt」を読み取り専用でオープンします。 # ファイルの内容を読み込みリストを返します。 for line in lines: f.close() |
試しに「Yahoo!」をスクレイピングしたtext.txtファイルを読み込んでみます。
(pyenv) [test@SAKURA_VPS scraping]$ python edit_text.py <!DOCTYPE html><html lang=”ja” class=”is-android”><head> <meta charset=”utf-8″> <title>Yahoo! JAPAN</title>Yahoo! JAPAN <meta name=”description” content=”日本最大級のポータルサイト。検索、オークション、ニュース、天気、スポーツ、メール、ショッピングなど多数のサービスを展開。あなたの生活をより豊かにする「課題解決エンジン」を目指していきます。”> <meta name=”viewport” content=”width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0″> <link rel=”apple-touch-icon-precomposed” href=”https://s.yimg.jp/c/icon/s/bsc/2.0/y120.png”> <link rel=”canonical” href=”https://www.yahoo.co.jp/”> <link rel=”stylesheet” href=”https://s.yimg.jp/images/mtop/5.3.1/styles/top.css”> |
リスト形式とは
readlinesはリスト形式で返すということは、リストの中は以下のようになっているということです。
[‘test00′,’test01′,’test02′,’test03′,’test04’] |
以下のようにそのまま lines を出力するプログラムに変更したらどうなるのでしょうか。
# -*- coding: utf-8 -*- f = open(‘text.txt’, ‘r’) #for row in line: print(line) f.close() |
プログラムを実行します。
(pyenv) [test@SAKURA_VPS scraping]$ python edit_text.py
~ 省略 ~ |
確かにリスト形式で出力されています。
全体で1リストで、1行がリストの1要素になっています。
Webスクレイピングをして目的の要素だけ取り出す
前回のパート5で Web スクレイピングをしてテキストファイル(text.txt)に出力するプログラムを作成しました。
【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(URLを引数で受け取る)【Part.5】
【Webスクレイピングをしてテキストファイル(text.txt)に出力するプログラム】
(pyenv) [test@SAKURA_VPS scraping]$ vi sele_test.py # コマンドライン引数を取り込み args に格納します。 # リストの数を調べます。 # リストの数をチェックします。 # コマンドライン引数の2番目を取得して page_url 変数に格納します。 dcap = dict(DesiredCapabilities.PHANTOMJS) # ユーザーエージェント driver = webdriver.PhantomJS(desired_capabilities=dcap) time.sleep(10) # 結果をファイルに出力する # webdriverを閉じます。 |
ここで出力したソースコードは先ほどのプログラムでリスト形式で出力されます。
ここから目的の文章だけ抽出します。
■欲しい情報
- タイトル
- 本文(本文の更に欲しい情報を抽出)
■処理の流れ
- リスト形式のデータを1行ずつ読み込む
- タイトルのタグを見つける ← if文 & search 関数
- タグを外してタイトルだけ抽出する ← search 関数
search 関数
search 関数は、文字列全てを検索して、抽出したい文字列が存在するかどうかを判定します。
正規表現を使用するため「re」ライブラリをインポートします。(import re)
他に文字列を検索したり、置換する関数
match 関数
findall 関数
finditer 関数
sub 関数
search 関数は2種類あった
間違えやすい部分です。
search 関数は2種類あります。
- find() ← 文字列.find(検索したい文字列)
- re.search() ← オブジェクト = re.search(正規表現, 文字列)
参考にさせていただいたサイト
UX MILK
再度処理を確認
if 文で探したい文字列を検索する
↓
見つかったら「真(true)」を返す
↓
その要素から欲しい文字列のみ抽出する
if 条件式:
■数字の場合
条件式: ← a == 10: ← a が 10 の場合
■文字列の場合
test = ‘python_test’
if test == ‘python_test’: ← 文字列の場合
■文字列の中に特定の文字列が含まれるかどうか確認する場合
※in は「部分一致」です。
【部分一致のため True】
test = ‘python_test’ if ‘python’ in test: print(‘True’) else: print(‘False’) |
【完全一致のため True】
test = ‘python_test’ if ‘python_test’ in test: print(‘True’) else: print(‘False’) |
【全く一致しないため False】
test = ‘python_test’ if ‘pyhon’ in test: print(‘True’) else: print(‘False’) |
特定の文字列だけ削除する
今度は逆に特定の文字列だけを削除する場合です。
■replace 関数
文字列.replace(‘変換元’,’変換後’)
■sub 関数
import re ← 正規表現
text.txt = ‘文字列’
re.sub(‘正規表現’,’変換後’,文字列)
Pythonでシングルクオテーションとダブルクオテーションの違い
突然だけど、Python で
- シングルクォーテーション(’)
- ダブルクオォーテーション(”)
の違いは何かあらためて気になりました。
以前、調べたけどすでに忘れています。
【参考にしたサイト】
https://python.g.hatena.ne.jp/muscovyduck/20080701/p2
- Ruby とは違い Python では「シングルクォーテーション」と「ダブルクォーテーション」に違いはなし
- 「シングルクォーテーション」で囲った文字列の中で「ダブルクォーテーション」を文字列として使える
- 「ダブルクォーテーション」で囲った文字列の中で「シングルクォーテーション」を文字列として使える
- 「シングルクォーテーション」の中で文字列として「シングルクォーテーション」を使いたい場合は「\」でエスケープする
- 「ダブルクォーテーション」の中で文字列として「ダブルクォーテーション」を使いたい場合は「\」でエスケープする
現在勉強している本&参考にしている本
Seleniumでどうすればいいのか分からなくなった時に読む本です。
サンプルプログラムは Java で書かれていますが、オプションや構文などは Python でも役に立ちます。
Pythonでどうやって Web スクレイピングをすればいいのか参考になる本です。こちらもどうすればいいのか迷った時に読む本です。
今までの連載
【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.1】
【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.2】
【Python】Python 3.6 & Selenium WebDriver & headless でスクレイピング【Part.3】
【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(find系操作)【Part.4】
【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(URLを引数で受け取る)【Part.5】
【Python】Python 3.6 & Selenium WebDriver & PhantomJS でスクレイピング(ファイルを読み込み文字列を抽出する)【Part.6】
まとめ
まだまだ先は長いです。
コメント