最近映画視聴記録がどうのという記事を書いていたのですが、映画関連で昔パルプフィクション絡みのやつを書いたことを思い出しました。
内容はタイトルの通りなのですが、以前の記事ではやり残しがありました。
プログラム歴も増えてきたので今なら出来るっしょということでリメイク版です。
前回のおさらい
- 台本上のfワードは169個
- やり残し
- セリフの成形
- 件数の表示
- 誰が何回言ったかのサマリ
コード
今回は全処理関数化してライブラリ的に呼び出せる様にしました。
(わざわざ呼び出して使う機会は無いと思うが)
引数の値もう少し統一感出せばよかったな。
今回も一応全編通して伏字にします。
from bs4 import BeautifulSoup import re import collections def create_quote_list(): with open('Pulp-fiction.html', 'r', encoding='utf-8') as f: soup = BeautifulSoup(f.read(), 'html.parser') lines = [] for x in soup.findAll('b'): lines.append((x.text, x.next_sibling)) return lines def into_list(l, chara, quote): shaping_charactor = chara.replace("\n", "").replace(" ", "").replace("(O.S.)", "") if shaping_charactor == 'CLOSEUP・MIA': shaping_charactor = 'MIA' l.append([shaping_charactor, quote]) def scraping_words(script_list): s_reg = re.compile('.+[fF]xxk.+') flist = [] for l in script_list: split_sentense = re.split('[,.!?]|and', str(l[1])) for x in split_sentense: w = re.search(s_reg, x) if bool(w) is True: s = w.group().replace("\n", " ").replace(" ", "") if 'AND' in l[0]: for y in l[0].split('AND'): into_list(flist, y, s) else: into_list(flist, l[0], s) return flist def fcounter(l): max_c, max_w = shapes(l) clist = [] for x in l: clist.append(x[0]) c = collections.Counter(clist).most_common() for x in c: c, w = x print(c.ljust(max_c), w) def shapes(l): max_c, max_w = 0,0 for f in l: if len(f[0]) > max_c: max_c = len(f[0]) if len(f[1]) > max_w: max_w = len(f[1]) return max_c, max_w def fquote(l): max_c, max_w = shapes(l) n = 1 for x in l: print(n, x[0].ljust(max_c), x[1].ljust(max_w)) n +=1 def main(): lines = create_quote_list() flist = scraping_words(lines) print('*' * 10, 'print f word list', '*' * 10) fquote(flist) print('*' * 10, 'print f word count', '*' * 10) fcounter(flist) if __name__ == '__main__': main()
スクリプト叩いて終了では味気無いのでインタラクティブシェルでインポートして少し見ましょう。 本当はこの呼び出し方は非推奨です。
>>> from pulp import *
スクレイピング対象
前回と同じくimdbのサイトにscriptがあるので、これをダウンロードしてつかいます。
https://imsdb.com/scripts/Pulp-Fiction.html
スクレイピングのライブラリはBeautifulSoupです。
スクレイピング処理も呼び出して格納。
>>> lines = create_quote_list()
HTML構成
上記サイトのscriptファイルはしっかりと階層化はされてなくて、 bタグでシチュエーションや登場人物、次の階層(タグなし)に状況やセリフが書かれています。 タグが無くてもnext_siblingというmethodで取得できます。 create_quote_list()内でbタグとその次のセリフを取得してます。
for x in soup.findAll('b'): lines.append((x.text, x.next_sibling))
取得した値はこう。
>>> lines[0] (' "PULP FICTION"\n', '\n By\n\n Quentin Tarantino & Roger Avary\n\n') >>> lines[10] (' YOUNG WOMAN\n', ' You sound like a duck.\n (imitates a duck)\n Quack, quack, quack, quack, quack, \n quack, quack...\n\n') >>> lines[20] (' YOUNG WOMAN\n', ' Did they hurt the little girl?\n\n')
スペース、改行記号の処理は別関数のshapingで行います。
ワードの取得
正規表現でワードと前後の文を抽出します。
4文字だけだと同じ文字が続くだけなので、結構バリエーションが出てくるのでせっかくだし前後も取ることにしました。
/w+等使って文章ごとに取りたかったのですが特殊文字や余剰スペースの処理で上手く全件ヒットとはならなかったのでフレーズごとに取得してます。
>>> f = scraping_words(lines) >>> f[0] ['YOUNGMAN', ' I sound like a sensible fxxking man'] >>> f[10] ['YOUNGMAN', ' fxxk it'] >>> f[100] ['JULES', " Don't you fxxkin' do "] >>> f[20] ['VINCENT', " but you're in the same fxxkin' "]
少し短いですが誰がどんな感じのこと言ってるかの雰囲気はわかります。
カウントのためリストに格納
上記と同じくscraping_words()の処理の話ですがカウントできるよう取得項目を人物、セリフに分割してリストにいれていきます。
文章を正規表現で抜き出すというのはやはりブレが出るため難しく、フレーズごとに分割してから対象のワードをひっかける方法にしました。
(件数が合わなくてあれ?となり何回か方法を施行しました)
一件だけ2人が同時に叫ぶ所がありますが、人物をカウントしたいのでここもさらに分割してます。
def scraping_words(script_list): s_reg = re.compile('.+[fF]xxk.+') flist = [] for l in script_list: split_sentense = re.split('[,.!?]|and', str(l[1])) for x in split_sentense: w = re.search(s_reg, x) if bool(w) is True: s = w.group().replace("\n", " ").replace(" ", "") if 'AND' in l[0]: for y in l[0].split('AND'): into_list(flist, y, s) else: into_list(flist, l[0], s)
また、スクリプト上で登場人物の表記が少しブレるので修正します。
セリフだけで画角にいないと台本に(S.O.)と言う表記が付くらしいです。
あとミアがCLOSEUPと付くシーンが一件だけあるのでこれも修正。
これらを取り除いてリストに入れるのがinto_listです。
後でアウトプットは出てくるのでコードだけおさらい。
def into_list(l, chara, quote): shaping_charactor = chara.replace("\n", "").replace(" ", "").replace("(O.S.)", "") if shaping_charactor == 'CLOSEUP・MIA': shaping_charactor = 'MIA' l.append([shaping_charactor, quote])
何回言ったかのカウンタは別関数でまとめます。
def fcounter(l): max_c, max_w = shapes(l) clist = [] for x in l: clist.append(x[0]) c = collections.Counter(clist).most_common() for x in c: c, w = x print(c.ljust(max_c), w)
出力
最後にアウトプット。
まずはfワードを全件出します。
罵詈雑言の嵐です(笑)
>>> fquote(f) 1 YOUNGMAN I sound like a sensible fxxking man 2 YOUNGMAN takin' the same fxxkin' risk as when 3 YOUNGMAN fxxkin' A it worked 4 YOUNGMAN but a fxxkin' phone 5 YOUNGMAN lift a fxxkin' finger 6 YOUNGMAN fxxkin' speak English 7 YOUNGMAN don't know what it fxxkin' means 8 YOUNGMAN one of those gook motherfxxkers' 9 YOUNGMAN fifteen fxxkin' generations 10 YOUNGMAN counter with a fxxkin' Magnum 11 YOUNGMAN fxxk it 12 YOUNGMAN gonna really give a fxxk you're 13 HONEYBUNNY Any of you fxxkin' pricks move 14 HONEYBUNNY motherfxxkers 15 JULES man ・I'm fxxkin' goin' 16 VINCENT they wouldn't know what the fxxk a 17 VINCENT they fxxkin' drown 'em in it 18 VINCENT We should have fxxkin' shotguns 19 JULES Marsellus fxxked his ass up 20 VINCENT fxxk her 21 VINCENT but you're in the same fxxkin' 22 JULES the same fxxkin' thing 23 JULES ain't even the same fxxkin' sport 24 JULES massages ・I'm the foot fxxkin' 25 JULES fxxk you 26 JULES fxxk you 27 JULES motherfxxkin-house 28 JULES fxxkin' up the 29 JULES Motherfxxker do that to 30 JULES I'd kill'a motherfxxker 31 VINCENT That's what's so fxxkin' 32 VINCENT fxxkin' Marsellus knew it 33 VINCENT shoulda known fxxkin' better 34 VINCENT his fxxkin' wife 35 JULES You'a smart motherfxxker 36 BRETT are about how fxxked up things got 37 JULES English-motherfxxker-can-you-speak- 38 JULES motherfxxker 39 JULES Then why did you try to fxxk 'im 40 JULES Ya tried ta fxxk 41 MARSELLUS motherfxxker 42 MARSELLUS that's a hard motherfxxkin' fact of 43 MARSELLUS motherfxxkers who thought their ass 44 MARSELLUS fxxkin' wit ya 45 MARSELLUS fxxk pride 46 VINCENT man's fxxkin' wife 47 LANCE But this one's a fxxkin' 48 LANCE any ol' day of the fxxkin' week 49 LANCE Coke is fxxkin' 50 LANCE in a big fxxkin' way 51 VINCENT You know what some fxxker did to it 52 VINCENT fxxkin' keyed it 53 LANCE that's fxxked up 54 VINCENT out five fxxkin' days ・five days 55 VINCENT some dickless piece of shit fxxks 56 LANCE They should be fxxkin' killed 57 LANCE You don't fxxk 58 VINCENT What the fxxk is this place 59 VINCENT That's a pretty fxxkin' 60 VINCENT but it's pretty fxxkin' 61 MIA shit the fxxk up for a minute 62 MIA like it's on fxxking fire) 63 JODY I thought you told those fxxkin' 64 LANCE tell this fxxkin' asshole right now 65 LANCE this fxxkin' late 66 VINCENT fxxkin' trouble man 67 VINCENT fxxkin'Doing on me 68 LANCE fxxkin' joking with you 69 LANCE be bringing some fxxked up pooh-butt 70 LANCE Then bite the fxxkin' bullet 71 LANCE She ain't my fxxkin' problem 72 LANCE fxxked her up 73 LANCE your car in my fxxkin' house 74 LANCE fxxkin' phone ・ 75 LANCE that fxxked up bitch in my house 76 VINCENT This fxxked up bitch is Marsellus 77 VINCENT Now if she fxxkin' 78 JODY What the fxxk's goin' on 79 JODY here being nobody knows what the fxxk they're doing 80 LANCE Get the fxxkin' shot 81 VINCENT Get the fxxkin' shot 82 VINCENT I'm not fxxkin' stoppin' you 83 LANCE My black fxxkin' medical book 84 VINCENT fxxk the 85 VINCENT Quit fxxkin' around man 86 VINCENT This ain't a fxxkin' joke man 87 MARSELLUS this motherfxxker 88 FABIENNE Shut up fxxk head 89 BUTCH Yes I've fxxkin' looked 90 BUTCH What the fxxk do you think I'm doing 91 BUTCH that was my father's fxxkin' 92 BUTCH all I gave a fxxk about was my watch 93 BUTCH Of all the fxxkin' things she coulda 94 MARSELLUS I'm pretty fxxkin' far from 95 BUTCH fxxk the bags 96 BUTCH we gotta hit the fxxkin' road 97 JULES blowing them all away while they're fxxkin' around 98 VINCENT Why the fxxk didn't you tell us about 99 JULES We should be fxxkin' dead right now 100 JULES We should be fxxkin' dead 101 JULES Don't you fxxkin' do 102 JULES What just happened was a fxxkin' 103 VINCENT Chill the fxxk out 104 JULES We should be fxxkin' dead now 105 JULES I want you to fxxkin' acknowledge 106 JULES eyes are wide fxxkin' open 107 VINCENT What the fxxk does that mean 108 VINCENT ・you're fxxkin' freakin' out 109 JULES What the fxxk's happening 110 JULES Why the fxxk did you do that 111 JULES The car didn't hit no motherfxxkin' 112 JULES motherfxxker 113 JULES drenched in fxxkin' blood 114 JULES fxxk we're gonna go 115 JULES We gotta be real fxxkin' delicate 116 JULES What the fxxk did you just do to his 117 JULES didn't look like a fxxkin' Maxie 118 JULES fxxk it 119 JULES gourmet fxxkin' shit on us 120 JIMMIE how fxxkin' good it is 121 JIMMIE fxxkin' business 122 JIMMIE fxxkin' divorced 123 JIMMIE get fxxkin' divorced 124 JIMMIE ・don't fxxkin' Jimmie me 125 JIMMIE than get the fxxk out of my house 126 JULES fxxk up your shit 127 MARSELLUS No fxxkin' shit she'll freak 128 JULES motherfxxkin' "ifs 129 JULES motherfxxker 130 MARSELLUS I'm on the motherfxxker 131 THEWOLF the fxxk outta Dodge 132 JULES motherfxxker's tip-top 133 THEWOLF you better fxxkin' do it 134 THEWOLF clean the fxxkin' car 135 JULES This is some fxxked-up 136 JULES The motherfxxker who said that 137 VINCENT it's fxxkin' dangerous to be 138 JULES mushroom-cloud-layin' motherfxxker 139 JULES fxxk am I doin' in the back 140 JULES the motherfxxker should be on brain 141 JULES that water's fxxkin' cold 142 JULES motherfxxker 143 THEWOLF does a fxxkin' thing 'til I do 144 THEWOLF I drive real fxxkin' fast 145 JULES motherfxxker 146 JULES motherfxxkin' charmin' pig 147 JULES my fxxkin' car keys 148 JULES That's what's fxxkin' wit' me 149 VINCENT of fxxkin' zombies 150 VINCENT gonna be ・a fxxkin' bum 151 VINCENT Stop fxxkin' talkin' like that 152 HONEYBUNNY Any of you fxxkin' pricks move 153 HONEYBUNNY motherfxxkers 154 HONEYBUNNY Now mean fxxkin' now 155 HONEYBUNNY do it or fxxking die 156 PUMPKIN now git your fxxkin' ass 157 JULES Keep your fxxkin' mouth closed 158 PUMPKIN unload right in your fxxkin' face 159 HONEYBUNNY your fxxkin' head off 160 HONEYBUNNY gonna fxxkin' die bad 161 JULES And when motherfxxkers 162 JULES that's when motherfxxkers 163 JULES fxxkin' fried chicken 164 VINCENT What the fxxk's goin' on here 165 JULES Motherfxxker on it 166 JULES with "Bad Motherfxxker" embroidered on it 167 JULES That's my bad motherfxxker 168 JULES shut the fxxk up 169 JULES say to a motherfxxker 'fore you popped
169件で前回と同じ件数です。OK。
続いて何回言ったかカウンタ。
やはり出演シーンの多い主人公達が多いですね。
本当は同一人物がいるのですが一応ネタバレになるのでここは手つけずです。
>>> fcounter(f) JULES 59 VINCENT 35 LANCE 19 YOUNGMAN 12 MARSELLUS 9 HONEYBUNNY 8 BUTCH 7 JIMMIE 6 THEWOLF 5 JODY 3 MIA 2 PUMPKIN 2 BRETT 1 FABIENNE 1
OK。
成形もうまいこと効いていていい感じに出力できました!
まとめ
フタを開けてみると成形のコードがほとんどでスクレイピングや正規表現は全然やってませんでしたw
やはりセリフを正規表現で抜き出すというのは文章やワードなどかなりのバリエーションがあり難しいです。
前述しましたが結局フレーズ毎に区切ってからワードを抜き出すという方法に落ち着きました。
とりあえず望む結果になったのでよしとします。
さすがに前回より日が経っているだけあって積み残しの解決も出来たしコードの書き方も少しは綺麗に出来たかなと思います。
最近パルプフィクション見てないのですがこの記事書いてたらまた見たくなってしまいました。