公元2015 第28個秋天
九月的午後,微風吹動窗紗,從24樓看去遠處的白雲一朵朵的棉花糖浮在空中,兩個街角外教堂上的鐘敲響了第十三下。
X坐在桌前,雙層的書桌上擺滿了各種漫畫,電腦旁邊的《新世紀福音戰士》是他最近從舊物箱裡重新翻出來的,望了一眼窗外,閉上眼睛深深地吸了一口氣。
他又要換房子了,每到這個季節總是要重新換個地方,換一個身份,周圍都是陌生人才會讓他有安全感,這樣就沒有人會發現他的秘密。
開啟ZR租房的網站,房源的搜尋列表頁面映入眼前,適合自己的房子總是自己租不起的。但是X還是要從裡面挑選最優的。
Spider是個很不錯的選擇,Goquery也是個很好的選擇
軍刀工具 Goquery
採用dom的選取器文法,如果使用Chrome非常容易提取元素的選取器。
chrome 右鍵->檢查->選擇需要的dom元素->代碼上右鍵->copy->copy selector
安裝
go get github.com/PuerkitoBio/goquery
使用方法
讀取頁面內容產生Document
res, e := http.Get(url);if e != nil { // e}defer res.Body.Close()doc, e := goquery.NewDocumentFromReader(res.Body)if e != nil { // e}
使用選取器選擇頁面內容
doc.Find("#houseList > li").Each(func(i int, selection *goquery.Selection) { // 房屋名稱 houseName := selection.Find("div.txt > h3 > a").Text()}
或者可以使用直接選取的方式
// 擷取經緯度houseLat, _ := doc.Find("#mapsearchText").Attr("data-lat")houseLng, _ := doc.Find("#mapsearchText").Attr("data-lng")
反蜘蛛策略
常見的頁面元素價格,是類似<span>$5880</span>
這種實現方式,但是ZR採用了另外一種。
ta的價格是通過CSS樣式表對背景圖片的位移來實現的,例如價格¥2690
的實現:
<span style="background-position:1000px" class="num rmb">¥</span><span style="background-position:-90px" class="num"></span><span style="background-position:-210px" class="num"></span><span style="background-position:-0px" class="num"></span><span style="background-position:-240px" class="num"></span>
圖片地址是
images/price/0fcc0d83409c547d3a9d038cc7808fa3s.png
圖片的內容是
6532148907
那麼針對如上的情況X提出一個方案:根據位移量來轉換得到價格
這個思路是對的,但是仔細測試後,發現每次訪問,圖片的地址都會發生變化,對應的圖片裡面的數位排序也會發生變化。
這時X的嘴角露出了微笑,很明顯
- 圖片每次訪問都發生變化
- 價格的位移量資料也會發生變化
- 為了保證價格每次展示都一樣,那麼必須有一個跟圖片對應的數字轉換規則
結論
- 無法通過直接轉換方式
- 尋找這個圖片位移量和價格的轉換規則
於是X通過Chrome的search找到了價格元素修改的js代碼
var ROOM_PRICE = {"image":"//xxxx.com/phoenix/pc/images/price/0fcc0d83409c547d3a9d038cc7808fa3s.png","offset":[[3,7,0,8],[3,7,0,8],[2,3,0,8],[2,3,7,8],[2,0,2,8],[3,7,2,8],[2,2,7,8],[2,2,2,8],[3,6,7,8],[3,6,7,8],[2,8,2,8],[2,8,7,8],[3,7,0,8],[2,4,7,8],[2,5,7,8],[2,8,7,8],[2,5,7,8],[2,3,7,8]]};// 這一段不用看了,其實就是將圖片上的字元,按照上面ROOM_PRICE的規則,按照數組的索引取出來即可$('#houseList p.price').each(function(i){ var dom = $(this); if(!ROOM_PRICE['offset'] || !ROOM_PRICE['offset'][i]) return ; var pos = ROOM_PRICE['offset'][i]; for(i in pos){ var inx = pos.length -i -1; var seg = $('<span>', {'style':'background-position:-'+(pos[inx]*offset_unit)+'px', 'class':'num'}); dom.prepend(seg); } var seg = $('<span>', {'style':'background-position:1000px', 'class':'num rmb'}).html('¥'); dom.prepend(seg);});
通過上面這段代碼,整個反爬蟲策略就暴露無遺了,其實設計者也是心思巧妙。
OCR 解密之 Tesseract 超立方體
X 在筆記本上寫下了如下的話:
- 我們有瞭解密規則
- 有了待解密圖片
- 需要提取圖片內容,作為解密的字串,交由程式處理
於是利用到了另一款軍刀工具 Tesseract
介紹
Tesseract是一個光學字元辨識引擎,支援多種作業系統。Tesseract是基於Apache許可證的自由軟體,自2006 年起由Google贊助開發。2006年,Tesseract被認為是最精準的開源光學字元辨識引擎之一。
Tesseract 翻譯過來是 超立方體
安裝
這裡是Wiki :https://github.com/tesseract-...
Mac 下的安裝很簡單
brew install tesseract
安裝完畢之後可以解析下試試
➜ go tesseract ~/Desktop/7d9a5bb074a89f93a5b4e82bea5dc872s.png stdout --psm 62436851907
安裝Go的package
go get -v -t github.com/otiai10/gosseract
使用方法
直接上代碼了,調用很方便
package ocrimport ( "fmt" "net/http" "os" "github.com/otiai10/gosseract" "io/ioutil" "io" "bytes")func Parse(imageUrl string)(string) { f, _ := os.Create("s.png") defer f.Close() resp, _ := http.Get(imageUrl) defer resp.Body.Close() pic, _ := ioutil.ReadAll(resp.Body) io.Copy(f, bytes.NewReader(pic)) client := gosseract.NewClient() defer client.Close() client.SetImage("./s.png") text, e := client.Text() if e != nil { fmt.Println("error") } return text}
最終,使用OCR解密了圖片內容,再通過轉換才的到了真正的價格
{ "_id" : ObjectId("5b88dfa8644d03deebc6ba6a"), "name" : "天通苑中苑4居室-南臥", "image" : "http://img.xxxx.com/pic/house_images/g2m1/M00/66/82/ChAFB1uGM-KAZfN6AAQ6qYhGUtc084.JPG_C_264_198_Q80.jpg", "price" : "2290", "url" : "http://www.xxxx.com/z/vr/61676366.html", "size" : "13 ㎡", "floor" : "5/6層", "room" : "4室1廳", "loc" : [ "40.077562", "116.432684" ], "toilet" : 0, "balcony" : 1}/* 2 */{ "_id" : ObjectId("5b88dfa9644d03deebc6ba6f"), "name" : "天通苑中苑4居室-南臥", "image" : "http://img.xxxx.com/pic/house_images/g2m1/M00/4F/6E/ChAFBlt9cXaAY-38AARyYlEU6S4611.JPG_C_264_198_Q80.jpg", "price" : "2430", "url" : "http://www.xxxx.com/z/vr/61663763.html", "size" : "11.8 ㎡", "floor" : "5/10層", "room" : "4室1廳", "loc" : [ "40.077562", "116.432684" ], "toilet" : 0, "balcony" : 1}/* 3 */{ "_id" : ObjectId("5b88dfa9644d03deebc6ba74"), "name" : "天通苑本三區4居室-南臥", "image" : "http://img.xxxx.com/pic/house_images/g2m1/M00/5A/E5/ChAFBluBaA-APjRgAASBBLkpT0w953.JPG_C_264_198_Q80.jpg", "price" : "2790", "url" : "http://www.xxxx.com/z/vr/61666427.html", "size" : "25.5 ㎡", "floor" : "6/6層", "room" : "4室1廳", "loc" : [ "40.066064", "116.426734" ], "toilet" : 0, "balcony" : 1}
END
ZR如果想使用這種方式來做到反爬蟲,其實只是限制了一下反制門檻,但是設計很巧妙。其實本次也是初試Tesseract-OCR
這款軍刀工具。