0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

hy and BeautifulSoup4

0
Last updated at Posted at 2021-11-03

hy 言語で BeautifulSoup4 を使うサンプル。

(import re)
(import os)
(import csv)
(import requests)
(import [bs4 [BeautifulSoup]]) ;;;;★

(defn po [hoge]
    (print hoge :end " | ")
)

;################################################

(setv current_name (get sys.argv 2)) ;;;;★★
(if (not (.exists os.path (+ "./" current_name)))
    (do
        (os.mkdir (+ "./" current_name))
    )
    (print "drectory exists")
)

;################################################

(setv url (get sys.argv 1))  ;;;;★★★

;################################################

(setv uAgent {"User-Agent" "Mozilla/5.0 (Linux; Android 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36"})  ;;;;★★★★

(setv response (requests.get url :headers uAgent))  ;;;;★★★★
(.close response)
(setv html_text response.text)
;(po html_text)

;################################################

(setv soup (BeautifulSoup html_text "html.parser"))
(setv list_oj [])
                                                   
(setv linecount 0)
(for [titles (.find_all soup "a" "tooltip")]
    (setv title (re.search r"(?<=\>).*?(?=\<\/a)" (str titles)))  ;;;;★★★★★
    (if title
        (do
            (setv linecount (+ linecount 1))
            (po linecount)
           ;(print titles)
            (.append list_oj (.group title))  ;;;;★★★★★★
            (print (get list_oj (- linecount 1)))
            (print "---------------------------")
         )
     )
)

;;;(print list_oj)

(with [csvfile (open (+ "./" current_name "/title.csv") :mode "w")]
    (setv writer (csv.writer csvfile))
    (writer.writerow list_oj)
)

(setv page_title soup.title.string)
(print page_title)
(del soup)

特に python が得意ということはまったくないが、python で書くならこうだとかんがえてから分解して、語順をかえて hy の文法に当てはめていくのに慣れるまで時間がかかる。
閉じる方の ) はこういう(java 風)にポジショニングする必要はない。クローズを閉じるカッコで表現する(できる)ので、Python のバカげたインデント一択の文法からは解放される。
さらには、Hissp ( hy とは違うモジュールの Lisp 系言語)では、...

インデントでカッコなしで書くというニーズに対応しているらしい。カッコの場合は見えてるので数数える感性の問題になるが、Python のインデントはエディターと感性の境界の問題で、どうしてもわからないエラーの原因がインデントと空白文字との違いだったりするのは、エディターの設定についても注意を向けなくていけないということだが、こういうカッコで識別する限りは、全部白か黒という、なんのシンタックスハイライトもないエディターの未設定状態でも問題はないというのはメリットとしてある。それで Python として動く。
あとは、こっからここまで 100 行をためしにループに入れたいとかだと、Lua や Ruby などは頭( for とか while )とおしりに( end )付け足すだけでいいのですぐにやるが、Python だと明日にしようかなと思ったりするのでカッコで済ませられるのは、そういう感性の人にとってはいい。


このサンプルで ★ 、import 文の作り方でまず

(import [bs4 [BeautifulSoup]])

python だとこうとしか想像できないものだが

from bs4 import BeautifulSoup

え、それどうなんのかな とびびる。
語順です。前置詞の(ような) from が消えるとどういう語順で、ここは目的格、ここは主格的なものというように認識されるのか、Python と hy で対照したペアを数種類実例で見ないとわからない。


★★ コマンド入力の2つ目の文字列を変数に入れるとこ。

(setv current_name (get sys.argv 2))

python

current_name = sys.argv[2]

というように配列からインデックスを指定して get で取り出すというひとつのパターンをここに見る。
違うのだから慣れるしかない。見て慣れれば、そういうもんだという認識になる。

★★★

(setv url (get sys.argv 1))

Hy のコードは探してもググり力のない自分には出会えないのでパズルを考えるのに clojure のコードをググって見つけて観察するのがよいかもしれない。


★★★★

response = requests.get(url, headers=uAgent)

のように、dict をヘッダーに詰め込むようなよくあるのは

(setv response (requests.get url :headers uAgent))

:を使っていてキーワードにする。これも、パターンとして、そういうもんだとして、そうしよう。


★★★★★ regular expressions の箇所

(setv title (re.search r"(?<=\>).*?(?=\<\/a)" (str titles)))
title = re.serach(r'(?<=\>).*?(?=\/a)',str(titles))

★★★★★★ title は match オブジェクトになるので、python では文字列として取り出すのに title.group[0] とするといいので

Hy では (get title.group 0) かな ? と思ったが違った。
なので、title.group() で取り出すことにし

(.group title)

こうなってる。


関数の作り方のサンプルとして、

(defn po [hoge]
    (print hoge :end " | ")
)

これは python の print はそのままだと改行コードがくっついているので、改行なしの print がほしいときがよくある。
他の言語だと、 println と print で使い分けたりするものだと思うのだけど、じゃあどうするかというと

print("改行なしのプリント",end="")

というようにするらしい。
それを po という関数にして | をプリントの最後にくっつけて改行はしないというものを作った。

二文字にして print とは差別化して関数にしておく。

なんのデータか、どんなサイトかは重要ではないので、結果がこうなるとだけ記載しておく。

1 | Hidden Road of the Netherworld
---------------------------
2 | Player
---------------------------
3 | I've Become the Villainous Empress of a Novel
---------------------------
4 | My Secretly Hot Husband
---------------------------
5 | My Nanny Is Psionic
---------------------------
6 | The Silver Wolf
---------------------------
7 | Psychomachia
---------------------------
8 | Tales of Demons and Gods
---------------------------
9 | The Prince is a Giant Tiger!
---------------------------

また違う、機能するコードのサンプル。
carbon (2).png

はまりどころは、a タグのなかの href アトリビュートの値を取り出したい場合、hy でどうするかだった。

href = soup.find.a['href'] # Python 

href のアトリビュートが存在するかどうか、存在するなら取り出したい場合 dict に対する get でのアプローチ。悩ましい。

(setv el (.find_all soup "a"))
;;=> => el = soup.find_all('a')
;;(setv el (.find_all soup :href True)) => => el = soup.find_all(href=True)

(for [atag el]
  (if (.get atag "href") ;; これと
    (do
      (print (get atag "href")) ;;これは、違う get
      (print "")
    )
  )                                                                                            )

Screenshot_20211116-190545_kindlephoto-30320289.png


ここに高度さはまったくない。なぜなら Lisp の高度さをまったく理解していない、python もよく知らない人が Lisp 風にPython プログラムを書いているから。だから python プログラムに見える hy のコードになっている。

Yusuke Shinyama
新山 祐介 さんの翻訳された 「Lisp プログラマのための Python 入門」by Peter Norvig が参考になるかもしれない。

English 原文はこちら

少し、というのはクオリティに難癖をつけているのではなく、おそらくこれは schemer (ていうのかな ? Lisper から scheme を見ると. Perl だと Perler になるのかな ? Perlist ?)に向けて Python と Lisp 言語関係を分析したもので 2000年辺りに書かれたものだからだ。
Python ユーザーから Lisp を分析するのにも参考になったと思われるが、おそらくは Hy 言語は clojure からの影響で Python をベースに clojure に使用感をよせてあるだと思われるので、また別のスタンスからこの比較分析を見ることになるためだ。

つい先程、内容をざっと見た
tackman さんの出版されている「Hyショートイントロブック」電子版には spaceemacs での hy 用の設定など解説されているようです。

hyrule

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?