爬蟲攻防之前端策略簡析

看到一篇文章,介紹在反爬蟲過程中,前端工程師的各種腦洞,文章見這里
文章里介紹了幾個大的網站,在反爬蟲過程中,采取的各式各樣的策略,無不體現出前端工程師的奇葩腦洞。
還挺有意思的,就簡單分析了一下,針對每個方案,看看有沒有解決辦法,于是整理成博客,記錄一下。

1. 自定義字體形式

該方案是,自定義了一種字體,網頁中使用亂碼字符或者其他混淆字符,通過自定義字體的渲染成正確的顯示數據。

代表網站有貓眼電影和去哪兒手機端。

1.1 貓眼電影

今日票房

如上圖,是貓眼首頁今日票房欄的前10名統計(截圖只截取了前三名),其中的票房數據,對爬蟲來說是私密數據,于是,貓眼給“加密”了。

source

網頁代碼顯示的是一堆亂碼,都是方框。。。

我們通過瀏覽器的開發者工具查看該部分“方框”數字,發現是用了自定義的字體渲染成可視的數字的。

maoyan.3
maoyan.4

woff字體是網頁開放字體格式,詳細可參見 MDN

我們把這個woff格式的字體文件下載下來,看一下這個自定義的字體里有啥奧秘呢?

這里推薦一個在線的字體編輯工具:百度字體編輯器

將下載后的woff文件字體,在百度字體編輯器中打開:

baidu.font

好了,一目了然,這個字體文件里,采用隨機的Unicode編碼來定義了 0-9這幾個數字以及一個空白符和一個小數點,而且數字定義的順序不是固定的,Unicode編碼也不是連續的

也就是說,在HTML頁面源碼看到的方框,它的unicode應該和字體上的值是對應的,你可以用 charCodeAt()方法進行驗證一下。

如果說,woff文件是固定的,那么其實問題很簡單。但是,貓眼這個woff文件并不是固定的,而是隨機的。

如果,woff字體文件里定義字體的順序和實際數字順序一致,或者其unicode值的順序和真實數字是一致的,也簡單。但是,順序也是隨機的。。。

所以,難道就真的沒辦法搞了么?

當然不!!!任何能在頁面上顯示的,都可以搞。

找到python的一個庫 fonttools,可以解析成字體為 xml 文件,然后再根據xml里的信息找找:

其實百度字體編輯器代碼是開源的,它其中依賴了一個核心庫 fonteditor-core ,這個庫應該也能解析字體數據,但是我在實驗時,老是報錯解析錯誤,不知為何,有興趣的小伙伴可以自行研究一下,并分享一下研究成果,謝過。

from fontTools.ttLib import TTFont

font = TTFont('/Users/coolcao/Downloads/b0a53bf9d791622d4681b8344fd118f92088.woff')
font.saveXML('/Users/coolcao/maoyan2.xml')

生成的xml文件,有兩部分很重要:

<GlyphOrder>
  <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
  <GlyphID id="0" name="glyph00000"/>
  <GlyphID id="1" name="x"/>
  <GlyphID id="2" name="uniEABA"/>
  <GlyphID id="3" name="uniEB51"/>
  <GlyphID id="4" name="uniE06D"/>
  <GlyphID id="5" name="uniF88C"/>
  <GlyphID id="6" name="uniF012"/>
  <GlyphID id="7" name="uniF6C7"/>
  <GlyphID id="8" name="uniE373"/>
  <GlyphID id="9" name="uniF48F"/>
  <GlyphID id="10" name="uniE429"/>
  <GlyphID id="11" name="uniF4CA"/>
</GlyphOrder>

第一部分是字體概覽,定義了字體集中的name,注意,這里id和實際數字并無關系,并不是實際的數字0,1,2...等等。name是采用unicode定義的 ,和在百度字體編輯器中的正好是一致的。

<TTGlyph name="uniF4CA" xMin="0" yMin="-13" xMax="511" yMax="719">
  <contour>
    <pt x="130" y="201" on="1"/>
    <pt x="145" y="126" on="0"/>
    <pt x="216" y="60" on="0"/>
    <pt x="270" y="60" on="1"/>
    <pt x="332" y="60" on="0"/>
    <pt x="417" y="146" on="0"/>
    <pt x="417" y="270" on="0"/>
    <pt x="378" y="309" on="1"/>
    <pt x="337" y="349" on="0"/>
    <pt x="277" y="349" on="1"/>
    <pt x="251" y="349" on="0"/>
    <pt x="215" y="339" on="1"/>
    <pt x="225" y="416" on="1"/>
    <pt x="239" y="415" on="1"/>
    <pt x="296" y="415" on="0"/>
    <pt x="385" y="474" on="0"/>
    <pt x="385" y="535" on="1"/>
    <pt x="385" y="583" on="0"/>
    <pt x="322" y="646" on="0"/>
    <pt x="268" y="646" on="1"/>
    <pt x="217" y="646" on="0"/>
    <pt x="149" y="584" on="0"/>
    <pt x="139" y="518" on="1"/>
    <pt x="51" y="533" on="1"/>
    <pt x="67" y="623" on="0"/>
    <pt x="124" y="670" on="1"/>
    <pt x="182" y="719" on="0"/>
    <pt x="266" y="719" on="1"/>
    <pt x="324" y="719" on="0"/>
    <pt x="374" y="693" on="1"/>
    <pt x="423" y="669" on="0"/>
    <pt x="476" y="581" on="0"/>
    <pt x="476" y="485" on="0"/>
    <pt x="426" y="410" on="0"/>
    <pt x="377" y="388" on="1"/>
    <pt x="440" y="373" on="0"/>
    <pt x="511" y="281" on="0"/>
    <pt x="511" y="211" on="1"/>
    <pt x="511" y="118" on="0"/>
    <pt x="374" y="-13" on="0"/>
    <pt x="270" y="-13" on="1"/>
    <pt x="175" y="-13" on="0"/>
    <pt x="51" y="99" on="0"/>
    <pt x="42" y="189" on="1"/>
  </contour>
  <instructions/>
</TTGlyph>

第二部分是具體每個字體的座標集合信息,這里我只摘錄了其中的一個字符F4CA的信息,我們多刷新兩次頁面,拿兩個不同的woff文件,轉換成xml文件,對比會發現,雖然每次定義的unicode不同,順序是隨機的,unicode也不連續,但是,但是,但是,有一樣是相同的,那就是上面第二部分字體的座標信息。為啥一樣呢?因為每個數字樣式是固定的,所以畫出圖來座標必定是一樣的。

maoyan.7

好了同志們,到這里,基本就明朗了,我們可以人工先把幾個數字的座標點進行標記,然后每次刷新時,拿到新的woff字體時,通過fonttool將字體轉換成xml格式,根據座標點信息,判斷其uncode值分別是多少。然后再將代碼中的“方框”轉換成真實數字即可。

1.2 去哪兒手機端網頁

去哪兒手機端采用的方案和貓眼類似,都是用的自定義字體進行混淆。

但去哪兒采用的是ttf格式的字體文件。這是不同點一。

而且,去哪兒自定義的字體,采用的unicode也比較簡單,看下面:

去哪兒

去哪兒直接用的真實數字的uncode進行編碼,只不過順序和真實數字不是一一對應的,也就是說,網頁源碼中如果是 '183',實際顯示的數字卻是 '361'。

而且每次好像也是不一樣的。不過沒關系,只要能用 fonttool 將其轉換成xml文件,拿到里面的座標數據,那么,沒跑。

1.3 起點中文網

有一個小說閱讀網站,叫起點中文網,也是采用了自定義字體的形式,這也是在cnode上有一個小伙伴提問的,我這次也看了一下。

不看不知道,一看嚇一跳,拿到源碼里的“方框字”后,看了一下其 unicode 編碼,全是一個unicode編碼,如下面:

$ node test.js
94.37
d821
d821
d821
d821
d821

其中第一行94.37是真實顯示的閱讀數,后面的每一行是一個方框字對應的unicode編碼,當我看到結果是,崩潰了,都是一樣的,什么鬼。。。 同一個字符編碼,能渲染出不同的數字來???

怎么套路和貓眼和去哪兒不一樣呢?

從源碼中,看到,這段閱讀數加密的數字,使用了css 類名為 zxJBLkdl,順著源碼,找到類 zxJBLkdl 的定義部分,有這么一段代碼:

<p>
    <em>
        <style>
            @font-face { 
                font-family: zxJBLkdl; 
                src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.eot?') format('eot'); 
                src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.woff') format('woff'), url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.ttf') format('truetype'); 
            } 
            .zxJBLkdl { 
                font-family: 'zxJBLkdl' !important;     
                display: initial !important; 
                color: inherit !important; 
                vertical-align: initial !important; 
            }
        </style>
        <span class="zxJBLkdl">&#100181;&#100184;&#100186;&#100181;&#100185;</span>
    </em>
    <cite>萬字</cite><i>|</i><em><style>@font-face { font-family: zxJBLkdl; src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.eot?') format('eot'); src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.woff') format('woff'), url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.ttf') format('truetype'); } .zxJBLkdl { font-family: 'zxJBLkdl' !important;     display: initial !important; color: inherit !important; vertical-align: initial !important; }</style><span class="zxJBLkdl">&#100183;&#100185;&#100186;&#100181;&#100188;</span></em>
    <cite>萬總點擊<span>&#183;</span>會員周點擊
        <style>
        @font-face {
            font-family: zxJBLkdl;
            src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.eot?') format('eot');
            src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.woff') format('woff'), url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.ttf') format('truetype');
        }

        .zxJBLkdl {
            font-family: 'zxJBLkdl' !important;
            display: initial !important;
            color: inherit !important;
            vertical-align: initial !important;
        }
        </style><span class="zxJBLkdl">&#100181;&#100185;&#100187;&#100184;</span></cite><i>|</i><em><style>@font-face { font-family: zxJBLkdl; src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.eot?') format('eot'); src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.woff') format('woff'), url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.ttf') format('truetype'); } .zxJBLkdl { font-family: 'zxJBLkdl' !important;     display: initial !important; color: inherit !important; vertical-align: initial !important; }</style><span class="zxJBLkdl">&#100179;&#100186;&#100181;&#100188;</span></em>
    <cite>萬總推薦<span>&#183;</span>周
        <style>
        @font-face {
            font-family: zxJBLkdl;
            src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.eot?') format('eot');
            src: url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.woff') format('woff'), url('https://qidian.gtimg.com/qd_anti_spider/zxJBLkdl.ttf') format('truetype');
        }

        .zxJBLkdl {
            font-family: 'zxJBLkdl' !important;
            display: initial !important;
            color: inherit !important;
            vertical-align: initial !important;
        }
        </style><span class="zxJBLkdl">&#100188;&#100187;</span></cite>
</p>

在這段代碼里發現了貓膩,其采用的也是隨機字體的形式,比如此次刷新時的字體叫zxJBLkdl.woff,這不重要。

重要的是 <span class="zxJBLkdl">&#100181;&#100184;&#100186;&#100181;&#100185;</span>這一行,這是啥,這是使用了html轉義字符輸出了幾個不知名的方塊字,然后通過字體再渲染出真實的數字顯示。

這里和普通的 &lt;等不同,這里叫做實體編號,實際轉義字符都要轉成實體編號才能被瀏覽器識別,具體請參閱這里

可是為啥我拿到的unicode是一樣的呢?

答案還是得從字體文件里找。使用fonttool將字體文件轉換成xml,然后你就找到了下面的代碼:

<GlyphOrder>
  <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
  <GlyphID id="0" name=".notdef"/>
  <GlyphID id="1" name="period"/>
  <GlyphID id="2" name="zero"/>
  <GlyphID id="3" name="one"/>
  <GlyphID id="4" name="two"/>
  <GlyphID id="5" name="three"/>
  <GlyphID id="6" name="four"/>
  <GlyphID id="7" name="five"/>
  <GlyphID id="8" name="six"/>
  <GlyphID id="9" name="seven"/>
  <GlyphID id="10" name="eight"/>
  <GlyphID id="11" name="nine"/>
</GlyphOrder>

太明目張膽了,直接用英文來命名數字,再繼續找這幾個英文數字的定義,找到如下代碼:

<cmap_format_12 platformID="3" platEncID="10" format="12" reserved="0" length="148" language="0" nGroups="11">
  <map code="0x18751" name="eight"/><!-- ???? -->
  <map code="0x18753" name="two"/><!-- ???? -->
  <map code="0x18754" name="five"/><!-- ???? -->
  <map code="0x18755" name="three"/><!-- ???? -->
  <map code="0x18756" name="zero"/><!-- ???? -->
  <map code="0x18757" name="nine"/><!-- ???? -->
  <map code="0x18758" name="six"/><!-- ???? -->
  <map code="0x18759" name="four"/><!-- ???? -->
  <map code="0x1875a" name="period"/><!-- ???? -->
  <map code="0x1875b" name="one"/><!-- ???? -->
  <map code="0x1875c" name="seven"/><!-- ???? -->
</cmap_format_12>

這里應該就是每個字符和其十六進制編碼之間的關系了。將上面的轉義編號的數字部分轉換成十六進制,正好就是這十六進制的編碼,因為這轉義字符是“自定義的”,因此瀏覽器不能識別,只顯示方框,估計在拷貝的過程中發生異常,瀏覽器不能識別具體的字符,都是按照方框去拷貝的,所以出來的unicode都是一樣的。

到這里起點中文網的過程也明朗了,其實質和貓眼也是一樣的,只是過程和形式不大一樣而已。

1.4 小結

采用自定義字體的網站,思路都一致。

后端搭一套字體生成接口,隨機生成一個woff字體,然后返回這個字體文件,以及各個數字的unicode對應關系,前端頁面進行數據填充即可。

基本采用自定義字體的方式,都可以使用上面的思路去破解,先拿到一個字體文件,然后使用fonttool轉換成xml,人工拿到每個數字的座標,然后就可以寫程序,當拿到新的字體文件時,通過座標信息去判斷每個數字到底是多少。

還有一種方案,使用無頭瀏覽器進行截圖,然后使用OCR工具進行文字識別,但這種方案問題在于,OCR識別存在一定的錯誤率,因此并不完美。這里就不說了。

2. 元素定位覆蓋

這種方式太有意思了,給兩套數據,前面一套假的,后面一套真的,然后顯示時,通過css定位,將假的數據覆蓋掉,只顯示真實數據。

源碼

真實數據

這個代碼塊里面,第一個 <b> 元素中有三個<i>元素,其中0和8是假的,是被后面的兩個<b>元素的9和4覆蓋掉了,顯示的真實數據是 479 。

這種方式很有意思,但在反爬難度上,和第一種采用自定義字體的方式,略微低一點,感覺有點騙小孩的意思。

我們可以根據第一個b元素的寬度,以及后面b元素的寬度和偏移量來計算,拿到真正的值(實際瀏覽器不就是這樣工作的么)。

比如上面這個,第一個b元素的寬度是54px,左偏移 -54px,第二個b元素為18px,左偏移-18px,那么很明顯覆蓋的是第三個數字嘛,第三個b元素左偏移-54px,覆蓋的是第一個數字,這樣完全可以寫個程序自動判斷,拿到真實數字。

這個方式沒有寫具體代碼,但代碼應該不難寫,有興趣的可以試試。

3. 背景圖拼湊

還有一種形式是,使用背景圖片,然后給位置,截圖,拼湊出真實的數字。

如imweb這篇文章里提到的美團這種方式。但是我沒找到美團哪個頁面現在是這樣的,應該是美團現在改版了,現在都是直接顯示數字。

這種方式,和上面元素定位覆蓋差不多的思想,但稍微復雜點,先把背景圖片拿下來,然后再解析html拿到具體的 background-position具體的值,使用能夠解析圖片的類庫進行截取數字,拿到的數字是圖片格式的,沒辦法,這種只能在通過一次OCR識別了,圖片,真的沒辦法。

因為是圖片,所以與其那么復雜去解析每個位置是啥數字,倒不如直接通過無頭瀏覽器進行截圖,然后通過OCR識別來的直接,因為瀏覽器顯示的就是圖片,只能進行文字識別這條路了。

這種方式在破解時復雜點,還會存在一定的錯誤識別率,其實還是一種不錯的反爬前端方案。但有一點不好的地方在于,由于是使用的圖片,所以在顯示上,不如文字那么清晰,而且在瀏覽器縮放時,也會有一定的模糊,給用戶的體驗會不好,不如文字清晰。

4. 偽類元素代替

汽車之家現在使用的是偽類元素,將詞組拆開,使用偽類元素代替。

這種方式在搞起來,比上面字體要難感覺。

拿汽車之家舉例,偽類的類名是隨機的,而定義偽類的css樣式,是js動態生成的,搞起來比較麻煩。

沒有爬汽車之家的需求,不搞了,我在網上找到一篇關于搞汽車之家這種方式的文章,有興趣的同學可以看下: 反爬蟲破解系列-汽車之家利用css樣式替換文字破解方法

從最終的結果來看,是js動態獲取要替換的問題,然后動態替換了問題。而且現在汽車之家又升級了,要替換的文字也是動態獲取的,沒有任何標志,所以在實際操作起來,難度還是蠻大的。

汽車之家的前端,你可以的,佩服。。。

有興趣的同學真的可以搞一下,搞定這個真的很有成就感。

5. 添加干擾字符并隱藏

這類有微信公共號的文章以及全網代理ip這個網站。

微信公眾號

微信公眾號里面,左側下劃線的部分文字為干擾文字,使用css的透明度(opacity)將透明度設置為0隱藏顯示。

全網ip代理

全網代理ip這個網站,左側畫細框的部分為干擾文字,使用css的display:none隱藏不顯示。

這種方案的話,需要解析每個dom元素,并根據其css樣式進行選擇正確的字符進行拼裝。難度應該不大,沒具體實施。

6. 總結

這個周末主要的精力放到了搞自定義字體部分了,覺得這個特有意思,因為之前也遇到過,當時不知道咋弄。

爬蟲與反爬向來都是,道高一尺,魔高一丈。在反爬方面,除了在后端上設置反爬策略,如限制ip訪問頻率,限制登錄用戶訪問頻率等等,前端在反爬上,也絞盡腦汁做了不少動作。

還是那句話,反爬做的就是,不斷提升爬蟲解析出正確數據的成本,但沒辦法真正防止爬蟲。

對于爬蟲來說,任何你能從瀏覽器上看到的數據,爬蟲都能拿到,只是在拿數據時,難以程度有所不同而已。

希望該文章能給大家帶來一些思路,幫助大家在爬蟲與反爬蟲過程中,作出更多有創新性的工作。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,238評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,430評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,134評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,893評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,653評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,136評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,212評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,372評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,888評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,738評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,482評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,179評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,588評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,829評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,610評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,916評論 2 372

推薦閱讀更多精彩內容

  • 一、概念 參考網頁字體Serif和Sans-serif的區別及瀏覽器字體的設置CSS Font知識整理總結 1.F...
    合肥黑閱讀 6,323評論 0 12
  • HTML 5 HTML5概述 因特網上的信息是以網頁的形式展示給用戶的,因此網頁是網絡信息傳遞的載體。網頁文件是用...
    阿啊阿吖丁閱讀 3,987評論 0 0
  • 人們思想繆誤,自我中心……今天聽到這句話的時候,心里感覺被狠狠的擊中,這不就是說的是我嗎?回想進入贏家4年多...
    蓉心閱讀 478評論 0 2
  • 今天是歷法中的正月十五,窗外咚咚的籃球撞擊聲在此刻不知道為何顯得特別悅耳。 手頭的工作先擺到一邊去,我任性地給自己...
    Miss_soul閱讀 168評論 0 0
  • 內心空往外求。 這么多年就買了許多的重復的于我幾乎用不到的,它們個個如失寵的孩子,期待你來愛它。
    AA劉芳如閱讀 185評論 0 0