はじめに
本記事はRaspberry Pi 上にUbuntu20を入れ、dockerを構築しその中にスクレイピングを行うBOTの実行環境を作って動かすときにぶつかった問題に関してまとめたものである。
本記事に関して書いている本人がまだ初心者なため、間違っている部分やより効率の良い方法があるかもしれません。
解決したエラーは主に以下の3つ。
OSError: [Errno 8] Exec format error: '/root/.local/share/pyppeteer/local-chromium/588429/chrome-linux/chrome'
RuntimeError: Cannot use HTMLSession within an existing event loop. Use AsyncHTMLSession instead.
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
目次
はじめに
目次
環境
- requests-html の r.html.render() をした時のOS Error
- discordのイベントループ内で実行した場合の RuntimeError
- event loop 内でr.html.render() をした時に発生した RuntimeWarning:
環境
Raspberry Pi 4B+ 4GB
Ubuntu20.04
Docker version 19.03.8
docker内の環境
Python 3.9.4
pythonのパッケージのバージョン
discord.py 1.7.1
requests-html 0.10.0
nest-asyncio 1.5.1
1. requests-html の r.html.render() をした時のOS Error
問題
最初は実際にURLからデータを取得してウェブエンジンを用いて描画を行おうとした。
以下のようなコードを書き、実行したらエラーが発生した。
実行したコード
from requests_html import HTMLSession
url = 'https://www.google.com/'
session = HTMLSession()
r = session.get(url)
r.html.render()
print(r.html.text)
発生したエラー
# docker exec -it <コンテナID> python3 opt/test1.py
Traceback (most recent call last):
File "/root/opt/test1.py", line 6, in <module>
r.html.render()
File "/usr/local/lib/python3.9/site-packages/requests_html.py", line 586, in render
self.browser = self.session.browser # Automatically create a event loop and browser
File "/usr/local/lib/python3.9/site-packages/requests_html.py", line 730, in browser
self._browser = self.loop.run_until_complete(super().browser)
File "/usr/local/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/usr/local/lib/python3.9/site-packages/requests_html.py", line 714, in browser
self._browser = await pyppeteer.launch(ignoreHTTPSErrors=not(self.verify), headless=True, args=self.__browser_args)
File "/usr/local/lib/python3.9/site-packages/pyppeteer/launcher.py", line 306, in launch
return await Launcher(options, **kwargs).launch()
File "/usr/local/lib/python3.9/site-packages/pyppeteer/launcher.py", line 147, in launch
self.proc = subprocess.Popen( # type: ignore
File "/usr/local/lib/python3.9/subprocess.py", line 951, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/usr/local/lib/python3.9/subprocess.py", line 1821, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
OSError: [Errno 8] Exec format error: '/root/.local/share/pyppeteer/local-chromium/588429/chrome-linux/chrome'
原因
こちら が参考になった。
原因はpyppeteer がarm64版ではなくintel 64bit版をダウンロードしているらしい。
この問題はintelCPU上で環境を構築している人には出ないかもしれない。
解決法
別個にchromiumをダウンロードしてpyppeteerの参照先をダウンロードしたchromiumに向けるようにした。
Dockerfile のaptのインストールを行うモジュールにchromium を追加し(apt install chromium)、sedコマンドを用いてrequests-htmlライブラリのpyppeteer.launch()の部分を書き換えた。docker exec -it <ID> /bin/bash
で入り、ライブラリの場所は pip show requests-html
で特定した。
書き換えに用いたコマンド
sed -i -e "s@pyppeteer.launch(@pyppeteer.launch(executablePath='/usr/bin/chromium', @" /usr/local/lib/python3.9/site-packages/requests_html.py
buildの時にこのコマンドを実行するようにするといいかもしれない。
2. discordのイベントループ内で実行した場合の RuntimeError
##問題
今度はスクレイピングをdiscordのeventで行うために以下のようなコードを書き、実行したらエラーが発生した。
実行したコード
import discord
from requests_html import HTMLSession
TOKEN = '' #discordのトークン
URL = 'https://www.google.com/'
client = discord.Client()
@client.event
async def on_ready():
session = HTMLSession()
r = session.get(URL)
r.html.render()
print(r.html.text)
client.run(TOKEN)
発生したエラー
% docker exec -it <コンテナID> python3 opt/test2.py
Ignoring exception in on_ready
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "/root/opt/test2.py", line 13, in on_ready
r.html.render()
File "/usr/local/lib/python3.9/site-packages/requests_html.py", line 586, in render
self.browser = self.session.browser # Automatically create a event loop and browser
File "/usr/local/lib/python3.9/site-packages/requests_html.py", line 729, in browser
raise RuntimeError("Cannot use HTMLSession within an existing event loop. Use AsyncHTMLSession instead.")
RuntimeError: Cannot use HTMLSession within an existing event loop. Use AsyncHTMLSession instead.
##原因
どうやらHTMLSession はevent loop内では使えないらしい。代わりにAsyncHTMLSession を使えとあるが、import AsyncHTMLSession
に変えるだけではダメだった(そりゃそうだ)。
##解決法
結論としてはコードを以下のように修正した。ここでは問題解決の手順上r.html.render()をコメントアウトした。
import discord
from requests_html import AsyncHTMLSession
TOKEN = '' #discordのトークン
URL = 'https://www.google.com/'
client = discord.Client()
@client.event
async def on_ready():
session = AsyncHTMLSession()
r = await session.get(URL)
#r.html.render()
print(r.html.text)
client.run(TOKEN)
await を付け足さないといけないらしい。付け足さなかった場合にはrにはコルーチンオブジェクトが帰り、r.html.text等でエラーを吐くらしい。
3. event loop 内でr.html.render() をした時に発生した RuntimeWarning:
問題
- でsession.get() まではできるようになったがr.html.render() のコメントアウトを外すと以下のエラーが発生する。
% docker exec -it <コンテナID> python3 opt/test3.py
Ignoring exception in on_ready
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "/root/opt/test3.py", line 13, in on_ready
r.html.render()
File "/usr/local/lib/python3.9/site-packages/requests_html.py", line 598, in render
content, result, page = self.session.loop.run_until_complete(self._async_render(url=self.url, script=script, sleep=sleep, wait=wait, content=self.html, reload=reload, scrolldown=scrolldown, timeout=timeout, keep_page=keep_page))
File "/usr/local/lib/python3.9/asyncio/base_events.py", line 618, in run_until_complete
self._check_running()
File "/usr/local/lib/python3.9/asyncio/base_events.py", line 578, in _check_running
raise RuntimeError('This event loop is already running')
RuntimeError: This event loop is already running
/usr/local/lib/python3.9/site-packages/discord/client.py:350: RuntimeWarning: coroutine 'HTML._async_render' was never awaited
pass
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/usr/local/lib/python3.9/asyncio/base_events.py:1891: RuntimeWarning: coroutine 'BaseSession.browser' was never awaited
handle = None # Needed to break cycles when an exception occurs.
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
原因
原因はr.html.render() 。それ以上はわからなかった。
##解決法
こちら が参考になった。
r.html.render() を r.html.arender() に変えるだけであった。
#まとめ
今回初めて記事を投稿したのでいろいろ至らない部分等があると思いますが、優しくご指摘いただけると幸いです。
ちゃんとドキュメント読むことって大切です...
#参考にしたサイト等
https://teratail.com/questions/166849
https://github.com/psf/requests-html/issues/330