pagetakaBlog

最近リフォームと鳥取県日南町の記事多め。写真、PC、ネット等の話題も

Python:SeleniumをつかったWebスクレイピングでの失敗事項(1)。

<前説>

アラウンド70sといえばよいのか微妙な立ち位置の爺です。Win10(64)+Python3.7+SeleniumでWebスクレイピングをやろうと妄想(≒暴走)中です。

苦労の結果、目的のことができるようになりました(ほぼ錯覚)。特定サイトのサイト内検索を使ってヒットした記事見出しと対になるURLを取得する、という作業です。

耄碌爺がすることゆえ失敗続きでした。失敗例を本日は記事にします。

<パスを通す>

「フルパスを書く」というのは、ドライブ名から始まって対象となるファイルまで全部書くことなんですね。爺、PATHは、通り道、小道というような意味もあるので最終目的のプログラム名(ファイル名)の手前(フォルダ)までとか思っておりました。
ossan-tech.work
Webで仕事すると、フォルダ名まで書けばindex.htmlなどは自動で拾ってくれるので、悪い癖、思い込みがありました。index.htmlを書かなくても迷子にならないのはそのように設定がされている、ということなんですが、爺になると横着なことばかり身につくわけです、反省。

<sがつく場合、つかない場合>

SeleniumでWebスクレイピングすると、ほぼほぼ「driver.find_element_by_class_name()」などというのを使います。この時、「elements」「element」の二通りがあるのですね…。最初、そもそも別な存在とは思わず、使っておりました。
「s」は複数形の意味だろうと思うのですが、使い方も異なるというのは、だんだん後になってわかりました。

|elements|

こちらは、リスト(配列)を返します。対象が見つからなくてもエラー表示はないみたいです。でも、属性(attribute)で「text」などが使えない。爺のような、古~い「N88-BASIC」みたいなことで遊んでいた世代には、配列の理解も、オブジェクトという基本概念もなかなかしっくりこないというのが本音ですが、ともかく、文字はすぐ吐き出せない…ということみたいなのですね…。

|element|

こちらは、特定のというか最初に見つかった対象要素の値を取り込んでくれるんでしょうね。対象が無いと、そんなのない、といってエラーを返してくださいます。最初、これがわからなかったです。
対象要素の値は、属性(attribute)で「.text」などとすれば取得できたりしました。クリック(click)もこちらでつかえます。ま、複数形の方でクリックってどういう神経しているのだ、と問われそうですけど、爺の神経は相当経年劣化、不存在に近い状態、ということで、膝をポンと打つまでにかなりの時間を要したのでした。

<len(対象リストなど)便利>

何かの要素を取得したつもりになって作業進行したら、無いよ~、などというエラーにかなり痛めつけられました。存在をなにか簡単に得られる関数はないかと思っておりました。
len()がその仕事をしてくれそうです。これ、文字の長さ(数)のみを知らせてくれる、みたいな刷り込まれた印象があるのですが、対象リスト(配列)にある要素数もだそうです…。
一項前の「elements」と組み合わせたりして判断に使ってみました…。
note.nkmk.me

<リスト追記の違い、appendとextend>

Webスクレイピングし検索語がヒットすると何ページにもわたって該当ページの記事見出しがリンク付きで表示されます。
1ページ目に表示された、記事見出しとリンク先URLを読みだし、別々の変数に保管→2ページ目の同一作業
という作業は、追記をすることになります。ここで、appendとextendの違いがありました…。
「N88-BASIC」世代の爺的には「静的配列」のイメージが強く、個々の配列要素が一列にそれぞれ格納されると単純に思い込んでいます(それすら忘れている)。
qiita.com
www.javadrive.jp
使い方の違いをわかり、実際に吐き出される結果物を確かめるのが大切かと思った次第です。

<URLリストと見出しリストをひとつのリストにする>

下のスクリプト、単独では動きません。悪しからず。イメージだけつかんでいただければ。

    #単一列の別リスト(ふたつ)を、ひとつのリストの第一列、第二列にまとめる
    output_data = []
    dataX = [data_URLs,data_titles]   
    for d in zip(*dataX):
        output_data.extend(d)
        print(d)

URLがまとまったリスト(data_URLs)と、記事見出しがまとまったリスト(data_titles)があるとし、それぞれは単一列のリストで別物です。この二つを、URLをA列、見出しをB列に取り込んでひとつの新しいリスト(output_data)をつくろうと考えました。

上のスクリプト、先頭にでもdata_URLsとdata_titlesのリストを作ればprint(d)で画面表示してくれるかと思います。
「for d in zip(*dataX):」の魔法のような記述がキモなんでしょうね…。