見出し画像

とりあえずイマハコレガセイイッパイ230301

import requests
from bs4 import BeautifulSoup
import html5lib

parser = 'html5lib'

#サイトURL取得
site_url = "https://~"
print('start')
res = requests.get(site_url)
res.raise_for_status()

soup = BeautifulSoup(res.text,parser)
elems = reversed(soup.select(".a-link.m-largeNoteWrapper__link"))
for elem in elems:
    article_url = 'https://note.com' + elem.get('href')
    title = elem.get('title')
    print(title)
#記事ごとの本文を取得
    article_res = requests.get(article_url)
    res.raise_for_status
    article_soup = BeautifulSoup(article_res.text,parser)
    article_bodys = article_soup.find('div',class_="note-common-styles__textnote-body")
        
    article_lines = str(article_bodys).replace('<br/>','\n')
    article_soup2 = BeautifulSoup(article_lines,parser) 
    second_text = article_soup2.get_text()
    final_text = str(second_text).replace('【承前】',' ◆◆◆\n\n').replace('【続く】','\n')
    with open ("タイトル.txt","a",encoding="UTF-8") as f:          
        s = f.write(final_text)

最初に

 目標はわしの書いた「電波鉄道の夜」とか、書いてる「マッドパーティードブキュア」の本文を取得して、ある程度まとめた文章にして出力したい、ということだ。

 今のところ、「最初に読み込まれる記事のURLを拾って、その先の本文を少し整形してテキストに書き込むこと」まではできた。
 備忘録もかねて、部分を説明していく。
 あまりかっこよくないコードだけど、初心者が自分用に作ったものなので大目に見てほしい。あと、もっとこうしたらいいよ、みたいなのがあったらオネエ口調で優しく教えてくれるとばちくそ喜びます。

中身

import requests
from bs4 import BeautifulSoup
import html5lib

parser = 'html5lib'

 初期設定、requestsモジュールとBeautifulSoupモジュール、それにhtml5libを読み込む。モジュールの役割は多分次のようになる。
・requests:入力したURLからhtmlファイルを取得する。この時、手に入るファイルはtextファイルではない。
・BeautifulSoup:htmlのファイルのタグを判別していろいろ操作をしてくれる。
・html5lib:↑がhtmlを認識してくれるようにする。この役割をpaserというらしい。本当はBeautifulSoupの中に組み込まれてるはずだけど、なんか機嫌が悪いみたいなので、外部のモジュールさんの力を借りた。
 ここの最後の部分でparserにhtml5libを代入している。

#サイトURL取得
site_url = "https://~"
print('start')
res = requests.get(site_url)
res.raise_for_status()
soup = BeautifulSoup(res.text,parser)


 URLを見つけて分析してもらう部分。今のところノートの任意のタグ検索のページのURLを入れる。例えば「銀河鉄道の夜」とか。 
 print('start')はコンソールをわかりやすくするためにつけてるだけ。多分ちゃんとしたやり方とか見方をする人ならいらないはず
 requestsで指定されたurlからhtmlを引っ張ってくる。
 引っ張ってきた中身を変数resに入れてる。
 raise_for_statusの部分は呪文。urlが見つからなかったときに原因を調べて、返してくれる……らしい。
soup =~の行はBeautifulSoupで変数resの中身を分析した中身を入れてもらう。BeautifulSoupはresそのままだと認識してくれないので、.textをつけてpaserで調べてもらう。真面目に書くと「第一引数に分析したいオブジェクト、第二引数にその際に使用するparserを入れる」とかになるんだと思う。

elems = reversed(soup.select(".a-link.m-largeNoteWrapper__link"))
for elem in elems:
    article_url = 'https://note.com' + elem.get('href')
    title = elem.get('title')
    print(title)

 繰り返し処理を使ってとって来たい記事のurlとタイトルを取得する。
 変数elemsの中に、上のsoupで見つけてもらったhtmlを分析してもらって、それぞれの記事に共通するタグを見つけてもらって入れる
 今回はそれぞれの記事が".a-link.m-largeNoteWrapper__link"というタグを持っていたので、それを目印にさせてもらう。
 そうするとキーワード検索で出てくるページのそれぞれの見出しを見つけてくれる。
 それぞれについてまず変数article_urlにリンク先のurlを作る。elem.get('href')でそれぞれの記事に含まれるhref属性の先を手に入れて、省略されてる前半部分と合体させる。この変数は後で使う。
 次にチェック用でそれぞれのタイトルを引っ張ってきてコンソールに出力させてる。一応紹介記事が挟まったりとか、順番がなぜか入れ替わってた時に気が付くようにしてる。(紹介記事一回しか書かれたことないので無視してもよいかもしれない)
 あと、「新着順」で見つけちゃうけど、最終的に「古い順」に並べたいので、reversed()をつけて逆順から見つけてもらってる。

#記事ごとの本文を取得
    article_res = requests.get(article_url)
    res.raise_for_status
    article_soup = BeautifulSoup(article_res.text,parser)
    article_bodys = article_soup.find('div',class_="note-common-styles__textnote-body")

 さっき見つけた記事それぞれごとのurlのarticle_urlを調べていく。
 変数article_soupにまたBeautifulSoupで調べてもらったのを入れる。
 変数article_bodysにarticle_soupから見つけてもらった、本文に当たる部分を代入する。今回は'div'で"note-common-styles__textnote-body"というclassを持ってるところに本文が書いてあるので、それを取得してもらう。

 article_lines = str(article_bodys).replace('<br/>','\n')
    article_soup2 = BeautifulSoup(article_lines,parser) 
    second_text = article_soup2.get_text()
    final_text = str(second_text).replace('【承前】',' ◆◆◆\n\n').replace('【続く】','\n')

 上の状態のままだと、htmlの改行タグである<br/>が付いたままでひたすらずらーっと一行で戻ってきて読みづらいので、整えていく。
 まず、article_bodysをstr()に入れて文字列に変換して、<br/>をpythonの改行タグである'\n'にreplaceで入れ替える。文字列に変換しないと「この形のやつは変えれないよ」って怒られる。
 こうするためにはタグを残しておかないといけないのだけど、これ以降はタグはもういらなくなる。
 なので、もうタグとかは取っ払っちゃいたいので改めてもう一度Beautiful
Soupで分析してもらって、second_textにget_textでタグを取ってテキストだけになった状態の記事を戻してもらう。
 で、私の今回の小説の場合、全部【承前】で始まって、【続く】で終わってるので、それを区切り用の「◆◆◆」に置き換えて最終的な文章final_textに入れてもらう。

    with open ("タイトル.txt","a",encoding="UTF-8") as f:          
        s = f.write(final_text)

 ここまでで手に入れたfinal_textをテキストファイルにして保存する。タイトルにしてあるところに小説のタイトルを入れるといいと思う。
 今回の場合は「電波鉄道の夜」だね。
 後からどんどん書き足していくことになると思うので、付け加える用にモードは"a"で開く。あと、encodingはいらない場合もあるらしいけど、なかったらぐずりはじめたのでつけることにした。
 最後にfinal_textを書き込んでもらって作業は終了です。

まとめとか感想

 改めて説明しながら見直すとなかなか酷いコードだ。
 もうちょっと変数の命名ちゃんとしたほうが良いと思う。はい。
 自分で書いてて気になったのは二つくらいある。
・題名を検索ページで探してるけど、とんだ先の記事で見つけた方が汎用性が高い気がする。
・文章整形する部分ってもう少しきれいにならない? 一回文字列に変換してまたsoupに戻すのってなんかもっとスマートな方法あるんじゃないかと疑っている。イマハコレガセイイッパイ。ふーむ。

 本当に改めてみると、むちゃくちゃ恥ずかしいな。
 でも、こうして書いたの残して振り返ることが、後々もっといい感じにするために必要だとも思うのでとりあえず書いてまとめてみた。
 あと、やっぱり最初だからなのか、今扱っている/扱おうとしているデータがどういう形なのかがぱっとわからなくてエラーが出る状況が多かった気がした。こればかりは慣れるしかないのかなーと思う。

未来への展望

 このコードだと先頭の20記事までしか読み取ってくれない。
 多分「もっと見る」を押した後の記事を見つけてくれてないっぽい。
 これを解決するためのモジュールがseleniumというらしい。これはブラウザにいろいろ操作をしてもらって分析するモジュールっぽい。
 でも、今のところこれを使うのに必要なchromeのバージョンとchromedriverのバージョンが喧嘩をしているっぽくて、ちゃんと動いてくれない。chromeの最新バージョンが122でchromedriverのバージョンが123なんですよね。なんで? それとも本当はchromedriberが123でもちゃんと動くのにほかの何かが悪さをして動いてくれないだけなのかな?
 もう少し仲良くなろうと試みてみます。うーむ。
 無理そうなら手動でurlをまとめて食わせるしかない。やだー! でも、絶対そっちの方が早く終わるんだよな。やだー!
 
 というわけで、これが完成したら「電波鉄道の夜」をひとまとめにした版を出そうと思いますので、そちらもよろしくお願いします。

おわり

3/2追記

なんかいまchormedriverをダウンロードしなおしたら、122になってた!
選ぶとこを間違ってたのかな?
ともあれこれで先に進めるぜ。

この記事が気に入ったらサポートをしてみませんか?