發表文章

目前顯示的是 2018的文章

[Python] [網路爬蟲] 用 selenium 不用登入就能爬過 Facebook

圖片
因為某些原因決定來寫個爬蟲,可以計算 FB 某則貼文中某個關鍵字的數量,然後是可以在不登入的情況下使用的。這篇文章記錄了一些要處理、注意的東西,那麼我們就開始吧! 4/2 補 :因為 FB 網頁的原始碼有改動,所以程式碼有作更新,但內文還是舊的,因為重要的步驟都沒變,所以只更新文章底部放的程式碼。 使用 Selenium (搭配 Firefox driver )   首先來個 10 秒入門 Selenium: from selenium import webdriver driver = webdriver.Firefox(executable_path=r'<存放 Firefox driver 的路徑>') # 建立 driver 物件 driver.get(r'<你想爬的網頁>') # 連線至指定的網頁 driver.quit() # 關閉網頁並退出 driver   好的,這個範例應該挺淺顯易懂的,那我們要繼續下去了。 開始爬取 FB 貼文   當你在沒有登入的情況下開啟了一個 FB 貼文,過一小段時間會跳出這樣的畫面:   它擋住了我們要爬的文章!一定要想個辦法除掉 它。   ( 1/21 補 :現在的 FB 好像不會跳出這個大框框了,如果確定沒有的話,就可以跳過下一步) 尋找與等待:By、WebDriverWait   雖然我們迫不及待地想要按下那個「稍後再說」的按鈕,但這個大方塊並不是一開始就存在的,而是過了一段時間才會跳出來,那麼到底是多久呢?  不知道。   那我們要怎麼知道它已經出現了?幸好 selenium 有提供 WebDriverWait 物件,可以使用他來檢查某個條件是否已經達成,我們先看看程式碼: from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as ec from seleni

[C++] RTTI(執行時期型態資訊)的 Demangling

圖片
挽救回不來的進度(?)  這些日子懶到只有發幾篇歌詞翻譯,連一點點的技術性文章都沒有產出,為了確認我還活著而且沒有轉職(??),想說發一篇不久前看到 C++ 裡一個好用的函式。 RTTI,執行期型態資訊   這個應該很多人都已經知道了,只要引入 <typeinfo> 標頭檔,再使用 typeid 運算子就可以得知目前某個變數的型態資訊,在多型與動態型別方面很有用。      而其中,有個 name() 成員函式可以取得型態的名稱,用法如下: #include <typeinfo> // 略... int i; cout << typeid(i).name() << endl; // 輸出: i   如果你是使用 gcc 的話就會看到輸出為單個字母:i,這不難理解,就是 int 嘛,但是這樣呢? char *c = new char; // 字元指標 int foo(float a); // 接受一個 float 並回傳 int 的函式 string s; // 字串 cout << typeid(c).name() << endl; cout << typeid(foo).name() << endl; cout << typeid(s).name() << endl; // 輸出: // Pc // FifE // NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE   第一個就是指向 char 的 Pointer 嘛,那接下來...「FifE」? 我是知道 Five 啦;「NSt7...... EEE」 ......??   我彷彿看到了許多黑人問號。   會出現這麼奇怪的名字是因為 C++ 有一個叫做 Name Mangling 的機制,簡單說就是把型態名加入一些特色並改寫成一個不會與其它名字重複的技術,但是經過 mangle 的名字對我們人類來說實在不好理解啊!所以我們要介紹一個很好用的函式:abi::__cxa_demangle() Demangling:現出本名   在使用這個函式之前要先引入 <cxxabi.h&g

[歌詞翻譯] 天宿り - After the Rain

我又拖稿惹,這篇早在6月中就翻好了但一直忘記要發,就變成這樣了XD 這次試著翻了一直以來都很喜歡的歌- 天宿り ,在聽專輯的 XFD 時就很想聽整首的了,後來無意間找到了這首的音檔,於是我跟這首歌才能相遇(?),而這篇翻譯也才能誕生(??) 天 あま 宿 やど り 作詞・作曲:まふまふ 歌:そらる 強 つよ がってばかりで   意地張 いじは ってばかりで 總是在逞強  總是一意孤行 背 せ は 小 ちい さいままで   夕焼 ゆうや け 空 ぞら    暮 く れていく 背影仍然渺小  晚霞中的夕日  逐漸西下 臆病 おくびょう なままだな   泣 な き 虫 むし なままだな 依舊懦弱  依舊是愛哭鬼 あぜ 道 みち でふざけた  あの 頃 ころ から 変 か わらない 鄉間小路的笑鬧  從那刻起就不曾改變 いけないこととわかっている 不被允許的事我一直都知曉 許 ゆる されないとわかっている 不被原諒的事我也一直都明白 それでも 今日 きょう は 雨 あめ が 降 ふ るから 縱然那樣  在今日這下著雨的日子 雨宿 あまやど りをしていこう 一起去避雨吧 ああ 啊啊 借 か り 物 もの としても 即使身為借來之物 今 いま はただ 貴方 あなた が 愛 いと しくて 此刻還是只愛著你啊 知 し りたいこと 以外 いがい    知 し らないから 想知道的事物以外  什麼都不知道 このままでいよう 就這樣吧 人気 ひとけ のない 小道 こみち を   言葉 ことば も 無 な く 歩 ある いた 杳無人跡的小徑  默不作聲地走過 信 しん じ 合 あ えたあの 頃 ころ のように 就如同還能互相信任的那些時日 数 かぞ えるほどの 幸 しあわ せに   誇 ほこ れるものがあるのなら 要是有能向屈指可數的幸福誇耀的事物 同 おな じ 世界 せかい で  こんな 世界 せかい で 在同樣的世界裡  在這樣的世界中 愛 あい し 合 あ えた  それだけだ 得以相愛  僅此而已 この 雨 あめ が 止 や まない  ずぶ 濡 ぬ れの 世界

[歌詞翻譯] 傘を差して - Shaun the Sloth

早安w 這是我第一次嘗試翻譯歌詞,選了這首 Shaun the Sloth 寫的《 傘を差して 》,第一次聽到的是 Sou 翻唱的版本,覺得很輕快所以滿喜歡這首的,再加上網上找不到這首的翻譯,於是這篇翻譯就這樣誕生了。   先附上 nico 的連結:     本家: 【IA】傘を差して【オリジナル】     Sou 的試唱版: 【傾注感情】傘を差して 試唱了ver.Sou 傘 かさ を 差 さ して 撐起傘 作詞・作曲:鈴木将太 Drum:有利 繪圖:しずみ 動畫:椎菜 青 あお く 澄 す んでいた 空 そら が 通 とお り 雨 あめ を 降 ふ らせてしまったが 雖然原本晴朗湛藍的天空下起了陣雨 傘 かさ も 差 さ さず 歩 ある く 僕 ぼく らはどう 見 み えたかな 但傘也沒撐而走著的我們看起來怎麼樣呢 雨 あめ に 濡 ぬ れた 君 きみ よりも 君 きみ を 濡 ぬ らした 雨 あめ の 方 ほう がまだ 比起被雨淋濕的你 將你淋濕的雨更加 自分 じぶん に 近 ちか い 存在 そんざい な 気 き がしてたまらない 對於察覺到自己這樣親近的存在而不可自拔 やがて 晴 は れた 空 そら のよう 就像天晴不久那樣 微風 そよかぜ に 揺 ゆ れた 水溜 みずたま り 在微風下搖漾的水窪 濡 ぬ れた 靴 くつ が 残 のこ す 模様 もよう 濕鞋所留下的波紋 まるで 昔 むかし 描 か いた 落書 らくが き 彷彿昔日所畫的塗鴉 全部 ぜんぶ 忘 わす れてみたい 綺麗 きれい な 思 おも い 出 で さえ 想試著把全部都給忘掉 就連那美好的回憶 新 あたら しい 生活 せいかつ に 支障 ししょう を 来 きた してしまう 前 まえ に 在造成新生活的阻礙之前 棚 たな に 飾 かざ ってある 写真 しゃしん 立 た ては 今 いま も 裝飾置物架用的相框如今也 時折 ときおり 見 み る 度 たび 色 いろ んな 記憶 きおく が 舞 ま い 戻 もど るから 隠 かく さなきゃ 因偶爾的睹物思情而不得不隱藏起來啊 夜 よる が 来 く る 度 たび 互 たが いに 寂

[Python] *args 和 **kwargs 是什麼?一次搞懂它們!

在翻閱 Python 的函式庫時常常會看到定義參數的地方放了 *args 和 **kwargs 這樣的東西,這究竟是什麼呢?讓我們先談談函式參數的定義。 預設參數   一般的定義方法就不多說了,直接來看有預設值的參數: def plus(a, b, c=None): res = a + b + (c if c else 0) return res   預設參數的用處通常是實作函式重載用的,可以使一個函式在接受引數時更有彈性,而要注意的語法問題是:預設參數在函式定義時一定要放在非預設參數的後面。   但如果我們想實作無限版的 plus() 函式呢?總不可能一直增加預設參數吧!   這時候我們可以用「*」來將引數收集到一個 tuple 中。 * -收集至 Tuple   先來看看範例: def plus(*nums): res = 0 for i in nums: res += i return res   透過 * 收集的引數會被放到一個 tuple 中,所以我們可以使用 for 來對它進行迭代。   這樣就可以理解為什麼要使用 *args 這個參數了,但是 **kwargs 又是什麼呢?我們要先從關鍵字引數來說起: 關鍵字引數 Keyword Argument   在呼叫 print() 時,我們有時會指定 sep 參數做為分隔輸出的字元,或是使用 end 參數來更改最後的換行字元。像這樣不用理會參數的真正順序,而只要給定名字然後指定值的情況,就是在使用關鍵字引數。   如果我們要指定的參數太多而造成版面不簡潔的話,可以考慮使用「**」來拆解一個裝有參數名與值的 dict。 ** 第一招-拆解 Dict   原諒我使用這麼中二的小標題XDD   直接看實例應該就能懂了: dt = {'sep': ' # ', 'end': '\n\n'} print('hello', 'world', **dt) # 等同於 print('hello', 'world', sep=' # ', end=&

[Python] 關於變數與參考的二三事

圖片
寫過 Python 的人大概都知道,在複製 list 的時候最好不要直接指定,而要使用 copy 函式,但可能有些時候,我們還是會不小心觸發這個黑魔法,所以今天我們要來破解這個魔咒,看看到底背後藏了什麼祕密! 變數   首先我們要來看一下 Python 的變數到底是如何運作的,假設我們輸入了: x = 1   就代表我們把 x 的值指定為 1 了, 是嗎? 事實上並不是這樣的,而是讓 x 這個變數參考到了 1 這個物件,我們可以用 id() 函式來看看這個物件在記憶體中的位址究竟在哪: print(id(x)) # 2011157552   我們可以看到,有一個奇怪的數字被印出來了。而如果我們將 x 加上 1,也就是 x += 1 之後,再對 x 使用 id() 的話,我們會發現,輸出結果,也就是物件的位址變得不同了,這似乎和 C++ 這類的靜態語言很不一樣。   這個差別很重要嗎?可能在處理數值型態如整數之類的型態不太需要去注意,但在處理 list -也就是我們今天的主角時就很重要了。   進到下一個小節前,我們先來整理一下,不論你是不是已經完全懂了,我想拿個東西來比喻 Python 的變數:N次貼。變數就像 N次貼一樣,上面寫著變數的名字,然後我們讓他參考到不同的物件時,就像拿著這個 N次貼到處黏貼一樣,因此只要是黏到( 參考) 不同的東西(物件),就一定是在不同的位置上(記憶體位址)。   在這裡我們也可以看到為什麼 Python 的變數可以一下儲存整數,一下又是字串,因為就如同剛剛所說的,我們終究只是拿著 N次貼在到處黏而已,而這 N次貼上又沒有規定我們一定要黏在什麼東西上 不然就會爆炸什麼的(呃 ,所以我們可以把他黏到各種型態上面都沒問題。 List 的陷阱 (1)-指定「=」   接下來的小節中都會以上面 N次貼的概念來講解。當我們把一個參考到 list 的變數指定給另一個變數時: Lt = [1, 2, 3] Lt2 = Lt   看起來好像是我們把 [1, 2, 3] 複製了一遍,再指定給 Lt2,但實際上只是把寫著「Lt2」的 N次貼也貼到那個 list 上而已,我們可以透過 id() 來驗證。所以當我們對其中一個 list 做變動的話... 就會兩個變數一起被更改! 也 就是踏入黑

[演算法] [C++ / Python] 深度優先搜尋 Depth-First-Search - Part II

圖片
在上次趴one 裡面我們已經 以一棵彩虹樹(?) 來 解釋了 DFS 的基礎步驟,並且用 C++ 以及 Python 實作了相關的程式碼,這次我們要來看看圖的部分。 啊,在這之前,我們簡單的複習一下 DFS 的要素:           1) 選擇起始點           2) 進入 DFS 後,先判斷是否已經到終端,如果是的話,離開 DFS           3) 把這個節點設為已走訪過           4) 尋找下一個可行的節點並進入,回到 2) 圖 當然是要先畫一張圖啦:   為了方便討論,這是個無向圖,也就是每條路都是雙向道。那我們開始吧!一樣先選一個起點,這裡我們選  1 ,可以看到,與 1 相連的節點有  2  和  3  ,根據 DFS 的精神,我們一樣要選一個點來「 深 」入討論,這裡我們就選 2,並同時約定,之後若要從多個點選擇的話,以數字小的為優先。   於是我們拿 2 來進行下一次的 DFS,結果找到了  3 ,  4 。因為剛剛的約定,我們在這先選比較小的 3 來進行下一層的 DFS,並找到了  1 ,  5 ,    6   , 咦?1 號節點我們剛剛不是走過了嗎?沒錯,所以我們這次就不用理他,直接選 5 繼續吧。   接著我們就找到了   4   和   6  ,我們再接著選 4,結果發現他找到的 2 在前面就走訪過了,因此我們就返回到 5,並選擇 6 重新出發。結果發現,走 6 這條路也沒辦法找到還沒走訪過的節點,因此退回到 5。   而 5 呢?也找不到新的節點了,所以再退,就這樣一路退到 1,發現完全沒有新的節點,因此,圖的 DFS 到此結束。 程式碼實作 C++ void dfs(int now){ cout << now << " visited." << endl; for (int i = 1; i <= 6; i++){ if (!visited[i] && e[now][i] == 1){ // 如果還沒來過而且可以走到 visited[i] = true; dfs(i);

[C] 每天來點字串用法 (6) - atoi()、atol()、atof()

我放棄把每 5 篇合在一起的想法了,那樣文章會變得很長ˊˇˋ 今天要介紹很好用的函式: atoi()、atol():字串轉整數   所屬標頭檔: <stdlib.h>   函式宣告: int atoi( const char *str ); long atol( const char *str );   首先要注意到: 這次的標頭檔 並不是我們熟悉的 <string.h>,而是 <stdlib.h>。   這兩是個可以把字串中的有效部分轉換成整數、長整數的函式,而怎麼樣算有效呢?基本上要符合以下條件:           1) 可能有正負號 (+ / -)           2) 數字   如果這個字串的開頭有一些空格的話,這兩個函式會自動跳過;而如果在有效部分後面還有一些文字的話(例如小數點),函式將不會理會這些多餘的字。 atof():字串轉浮點數   所屬標頭檔: <stdlib.h>   函式宣告: double atof( const char* str );   這兩是個可以把字串中的有效部分轉換成雙精度浮點數的函式,而怎麼樣算有效呢?基本上要符合以下條件:           1) 可能有正負號(+ / -)           2) 數字(可能有小數點)           3) 可能以「e」、「E」來表示的科學計號           4) 無限:inf 或 infinity(忽略大小寫)           5) 非數:NaN (忽略大小寫)   如果這個字串的開頭有 空格的話,這兩個函式會自動跳過;而如果在有效部分後面還有一些文字的話( 不含 上述提到的記號),函式將不會理會這些多餘的字。   另外,如果沒辦法轉換的話,atoi()、atol() 會回傳 0,atof() 會回傳 0.0;而如果轉換後超出該型態可儲存的範圍,將會是 undefined behavior。   範例如下: #include <iostream> #include <cstdlib> #include <string> using namespace std; int main(){ cons

[C] 每天來點字串用法 (5) - strcat()、strncat()

圖片
好的,不知道又過了幾天(廢),終於要來到第 5 篇了。 strcat()、strncat():串接字串   所屬標頭檔: <string.h>   函式宣告: char *strcat( char *dest, const char *src ); char *strncat( char *dest, const char *src, size_t count );   看到這熟悉的命名,該不會跟 strcpy()、strncpy() 那組函式很像吧?沒錯,所以按照上次的慣例,我們先來看看 strcat()。   strcat() 有兩個參數,分別是 dest 和 src,而這個函式的功用是將 src 接到 dest 後面,再回傳 dest 指向的字串。那你可能會問:那原本 dest 的 '\0' 字元會跑去哪呢?答案是會被 src 的第一個字元(也就是 src[0])所取代,並在最後面補上一個 '\0' 來當做新字串的結束字元。   看到名字多了一個 n 的函式,你可能會猜,是不是這個 strcat() 也會造成緩衝區溢位的問題呢?沒錯,所以接下來要介紹比較推薦的函式:strncat()。   如果有看過之前那一篇的話,應該都已經知道這個函式要怎麼用了,他會多接受一個整數,作為控制最多串接的字元數。不過這裡的機制跟 strcpy() 有點不一樣:           1) 無論如何都會在最後放一個 '\0',而這個 '\0' 並不受 count 的限制。 也就是說,真正串接字元數的最大值 其實是 count + 1 。   讓我們來看看他們的使用範例: #include <stdio.h> #include <string.h> int main(){ // strcat char s1[8] = "hi ", s2[8] = "sky"; strcat(s1, s2); printf("%s\n\n", s1); // strncat char s3[8], s4[8]; scanf("%s%s&q