質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

4回答

2525閲覧

HTMLからJavaScriptとして実行される部分だけを抜き出す方法

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2017/11/22 06:16

編集2017/11/23 03:50

###前提
HTMLを入力したらJavaScriptの部分だけを抜き出すようなプログラムを作成したいです。
javascript自体が外部ファイル化している場合はひとまず無視してください。

用途は言えませんが、実現したい具体的なことは以下のとおりです。

###入力するHTMLファイル

html

1<HTML> 2<HEAD> 3</HEAD> 4<BODY> 5<a href="#" onclick="alert('OKOK'); return false;"></a> 6<script> 7document.write('ABCDEFG') 8</script> 9</BODY> 10</HTML>

修正(2017/11/22)
"が被って実行できないということなので'に修正

###抜き出しのプログラムを実行

JavaScript

1alert('OKOK'); return false; 2document.write('ABCDEFG')

###試したこと
XMLとして、JavaScriptが書かれている属性名や要素名で(script要素やonclick属性など)を指定して取り出す事はできましたが、HTMLの仕様としてJavaScriptが書かれる属性というのは結構たくさんありますので全部を指定して取り出すのは現実的でないと思っています。

###実現したいこと
できれば、JavaScriptエンジンとかJavaScriptだと認識できるようなライブラリなどを利用して簡単にJavaScript部分だけを取り出せればと思っております。言語はできればPythonで書きたいです。
みなさんのお知恵を貸してください。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lhankor_Mhy

2017/11/22 06:47

たとえば、「いろは」という文字列があったとして、ご存知のとおりjavascriptの文法として有効(識別子とみなされる)ですが、この場合はどうしますか?
退会済みユーザー

退会済みユーザー

2017/11/22 06:55

その識別子がブラウザのJavaScriptエンジンでJavaScriptの一部分として認識されるのであれば抜き出したいです。
Lhankor_Mhy

2017/11/22 06:58

ということは、「文字列がjavascriptとして文法上有効か」ではなくて、「HTMLをパースした時にjavascriptとして実行される部分か」という理解でよろしいですか?
退会済みユーザー

退会済みユーザー

2017/11/22 06:59

おっしゃる通りでございます。説明不足で申し訳ありません。
defghi1977

2017/11/22 07:31

script要素, onxx属性, href="javascript:", 次点でhtml imports, object/embed/iframeあたりを抜き出す感じかなあ
退会済みユーザー

退会済みユーザー

2017/11/22 12:24

やはり、要素や属性を抜き出すしか方法はないんでしょうか?seleniumみたいなWebDriverを使って、プラウザがHTMLをパースした時にJavaScriptとして実行すべき部分を抜き出す、みたいな方法はないですかねー?
defghi1977

2017/11/22 13:01

穿った書き方をするとevalを噛ませればscript要素以外にもスクリプトは仕込めるわけで, もう少し条件や用途を絞らないと解決策は見つからないかと
退会済みユーザー

退会済みユーザー

2017/11/23 03:49

evel関数も何かしらのスクリプトと認識されるとおもうので、中でどのようなスクリプを書いていてもJavaScriptで扱われる文字列として認識されるとおもうのですがどうなのでしょうか?ブラウザが使っているHTMLパーサーなどをプログラム内で使うことはできないんでしょうか?そうすればJavaScriptだと認識できるところというのはわかる気もするんですが。
guest

回答4

0

ベストアンサー

JavaScriptエンジンとかJavaScriptだと認識できるようなライブラリ

上記のようなものはHTMLパーサーがscript部分を抜き出した後に適用されるものだと思います。本件の焦点はjavascriptの構文ではなくHTMLの構文ではないでしょうか?精度のある結果を求めるならHTMLとしてパースし、結果のDOMからしかるべきelementのattributeやtextを抜き出す方法が妥当だと思います。ただ、そうしたものは本回答欄に書くには少々大きすぎる類のものではないかと思います。

JavaScriptが書かれる属性というのは結構たくさんありますので全部を指定して取り出すのは現実的でない

仕様を網羅して全ての属性を指定するのが現実的でないかどうかはよくわかりませんが、しかし誰かがそういうプログラムを作るとしたら結局のところ「全部指定して取り出す」他はない気がします。つまり「ご質問のようなことを既に実装しているツールを探す」のでないなら全部指定することは避けられない気がします。

ただ、なんとなくですが「全てのelementの"on"で始まる名前のattributeを取り出せば少なくともイベント関連は網羅できそう」な気がするので、それで間に合わせるという妥協はできるのかも知れません。イベント以外でjavascriptを指定できる属性があるかどうか残念ながら自分は知りません。


ところで「対象のHTMLのパターンをある程度限定できる」ならそうまで厳密な手法をとらずともパターンマッチでそこそこの結果を得ることができると思います。

例えば以下のようなものでもなにがしかの役には立つかもしれません。個人的に手軽な気がしたのでNode.jsで試してみましたが、近頃のスクリプト言語では「テキスト処理が不得意」なんてものはないと思うのでなんでもよいと思います。

Javascript

1// ES2015(ES6) 2const fs = require('fs'); 3 4function* pickupScript(htmlFile) { 5 const html = fs.readFileSync('./sample.html', { encoding: 'utf8' }); 6 const elmatr = [ 7 // イベントの一覧は例えばhttps://www.w3schools.com/tags/ref_eventattributes.asp 8 // などみて列挙すれば列挙できなくはないと思います。100個に届かないぐらいと思います。 9 // window 10 "onafterprint", 11 "onbeforeprint", 12 ... 13 // misc 14 "onshow", 15 "ontoggle", 16 ].map(eventName => { 17 const p = '[^a-z_]' + eventName + '\s*=\s*(["\'])(.+?)\1'; 18 return new RegExp(p, 'ig'); 19 }); 20 for (let re of elmatr) { 21 for (let m; m = re.exec(html); ) { 22 yield m[2]; 23 } 24 } 25 26 // javascript以外であっても取り出してしまいます。 27 // 1行にscriptが1つしか書かれていないパターンしか想定していません。 28 // タグの構文は典型的と思えたパターンしか配慮していません。 29 const re2 = /^\s*<script(\s+[a-z]+\s*=["'].*?["'])*\s*>\s*$/i 30 const re3 = /^\s*</script>\s*$/i 31 let inside = false; 32 for (let line of html.split('\n')) { 33 if (!inside) 34 inside = line.match(re2); 35 else { 36 inside = !line.match(re3); 37 if (inside) yield line; 38 } 39 } 40} 41 42for (let g = pickupScript('./sample.html'), m; m = g.next().value; ) { 43 console.log(m); 44}

sample.html

HTML

1<HTML> 2<HEAD> 3 <script> 4 function onLoad() { 5 document.getElementById('a').innerHTML = 'ABCDEFG'; 6 } 7 </SCRIPT> 8</HEAD> 9<BODY ONLOAD='onLoad()'> 10 <a href="#" onclick="alert('OK'); return true;"></a> 11 <a href="#" onclick="alert('NG'); return false;"></a> 12 <div id="a"></div> 13</BODY> 14</HTML>

結果

text

1onLoad() 2alert('OK'); return true; 3alert('NG'); return false; 4 function onLoad() { 5 document.getElementById('a').innerHTML = 'ABCDEFG'; 6 }

投稿2017/11/22 12:52

KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/11/23 07:14

ワンラインになっている<Script>hogehoge()</script>からhogehoge()を抜き出す処理も追加してもらえませんか?nodeで結構ですので・・。
KSwordOfHaste

2017/11/23 07:29 編集

const re4=/<script>(.+?)</script>/ig; for (let m; m = re4.exec(html); ) { yield m[1]; } をpickupScript本体に追加するぐらいでしょうか。ただし上記のコードの意味を把握せずに使っていると落とし穴が(マッチできない・不当にマッチする)ことになりますのでそこはご注意を。yambejpさんがおっしゃるようにあくまで「そこそこの精度」でしかありませんので。 ---すみません、typoあったので直しました。
退会済みユーザー

退会済みユーザー

2017/11/23 07:27

ありがとうございます。正規表現苦手なので助かりました。
退会済みユーザー

退会済みユーザー

2017/11/23 08:16

''' const re2 = /^\s*<script(\s+[a-z]+\s*=["'].*?["'])*\s*>\s*$/i const re3 = /^\s*</script>\s*$/i const re4 = /<script>(.+?)</script>/i; let inside = false; let onelinescript = false; for (let line of html.split('\n')) { if (!inside){ inside = line.match(re2); onelinescript = line.match(re4); if(onelinescript){ // console.log(onelinescript[1]); yield onelinescript[1]; onelinescript = false; } }else{ inside = !line.match(re3); if (inside) yield line; } } ''' 先程のコードを参考に、上のように行が分かれているScriptタグを処理する部分でついでに、ワンラインのスクリプトタグも処理できるように改良しました。しかし、これでは<script>hogehoge()</script>は抜き出せても、<script type="text/javascript">hogehoge()</script>は抜き出せなかったので、re4の正規表現を ''' const re4 = /<script(\s+[a-z]+\s*=["'].*?["'])*\s*>(.+?)</script>/i; ''' このようにしたのですが、うまく抜き出せれません。訂正すべきところを教えてください。
KSwordOfHaste

2017/11/23 08:25

RegExp.execute(文字列)とすると、結果は配列になるのですが、正規表現の中に括弧でグループ化されている部分が以下のように2個あったとき /...(パターンA)...(パターンB).../ executeの結果は3要素となり、0番目がマッチした全体部分、1番目がパターンAの部分にマッチしたもの、2番目がBの部分にマッチしたものとなります。これはJavascriptに限った話ではなく、グループ化された正規表現のマッチ結果としてよく用いられる手法ですので覚えておくとよいと思います。さて変更されたre4にはグループが2つあり、興味あるのは2番目の方ですので、自分が挙げた最初のコメント中の変数mを用いるとm[2]と書けばよいです。
退会済みユーザー

退会済みユーザー

2017/11/23 11:52

なるほど!、すごい初歩的な事なのにご丁寧にありがとうございました。
guest

0

まず

<a href="#" onclick="alert("OKOK"); return false;">

クォーテーションが競合しているので、例示のonclickは実行できません。
またonclickが実行するものがかならずしもjavascriptとは言えません
加えてjavascript自体が外部ファイル化シている場合どういう仕様にしたいのかもわかりません。
総じて基本的には無理だとおもって差し支えないと思います。

逆に拡大解釈していいならonXXX=○○の箇所(トリガーはclick以外もある)と
<script~</script>までをそれぞれ正規表現などで抽出すれば
精度は低いですが文字列を取り出すことはできるとおもいます。

投稿2017/11/22 06:34

編集2017/11/22 06:36
yambejp

総合スコア114572

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Python にはスクレイピングのモジュールがあります。これで<script>のなかみを取り出すことができます。

https://qiita.com/itkr/items/513318a9b5b92bd56185

ここなど見てください。

投稿2017/11/22 12:24

sizumita

総合スコア196

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

とりあえず、javascriptでイベントを呼ぶ属性を出力するコードを書いてみました。
サンプル

javascript

1var onAttributes = Object.getOwnPropertyNames(HTMLElement.prototype).filter( x => x.startsWith('on') ); 2document.querySelectorAll('*').forEach( e => onAttributes.forEach( p => e[p] && console.log(e[p].toSource()) ) );

投稿2017/11/22 08:50

Lhankor_Mhy

総合スコア35865

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問