1 設計思考
1.1 關於爬取文章存儲的思考
- 第一,文章要抓取到本地;
- 第二,查詢文件大小,如果文件過大,超出多少M,則新建一個主題文件比如:file="./"+"微信文章_"+key+編號+".html"。我從多個html中提取信息,然后寫入到同一個html中。(可以參見精通python網絡爬蟲的第六章中的爬取微信搜索平台。但是本文遠比它復雜)
- 關於mongodb數據庫的設計:首先是:文章的url,標題,然后是md5編碼(用來避免重復抓取),接着是,文章在本地的存儲位置。就的file="./"+"微信文章_"+key+編號+".html"文件,然后是計數count。因為使用微信搜索平台的時候,不同的關鍵詞搜索,返回的結果中可能存在重復的文章,避免重復抓取。
其實,我也想過,以不同的key去微信搜索平台進行搜索,將返回的文章,存入到mongodb數據庫不同的collection中。然后,下次以該key去抓取文章的時候,要避免重復抓取,就可以去檢索mongodb數據庫,該key對應的collection。
但是有一個問題就是,不同的key進行搜索,比如:“如何追漂亮妹子”,”如何追漂亮女生”,這兩個搜索的有重復的文章。用上面的方式,相同url下的文章會放入不同的collection中。
雖然,本着朴實的態度,不同的key進行搜索得到的文件應該寫入到不同數據庫中,以表示這個key的搜索結果。
但是,本着為我負責的態度,(我不想看重復的信息),不同key下的文件,如果文章url存在重復,我也不會爬取。
所以,當一個人問,以一個key進行搜索的時候,查詢我的mongodb數據庫,很可能是少於直接使用微信搜索平台時的返回結果。比如,他問的是“如何追漂亮妹子”,但是微信搜索平台返回的文章列表呢,有些可能已經在之前key為“如何追漂亮女生”時,我為之建的mango數據庫和相應的存儲文件中了。所以,爬蟲的時候,我就不爬了。
所以,請記住這種情況。我寫爬蟲純粹是為了興趣和為了要到自己的數據,瀏覽大量的信息,而不是為了什么狗屁嚴謹。
1.2 關於爬取圖片的思考
首先,我設計的終極目標就是爬取生成的本地文件,還能展示原有網頁的圖片。單純的urllib獲取的網頁都是靜態數據,一方面,某些圖片的src還沒有加載,還存放在data-src中。比如,親測微信搜索平台的某篇文章,在瀏覽器還沒有向下翻的時候,圖像的地址是寫在data-src。這就是一種預加載機制,避免一開始就加載大量圖片導致網頁整體加載速度過慢。當瀏覽器向下滑動的時候,圖片的src會被js操作改變,從而開始加載圖片。所以src中開始出現圖片的真實url地址。這也是我之前開發網站的常用做法。
可以看到,通過瀏覽器側邊欄滑動的話,已經加載的圖片,src屬性會等於data-src屬性。但是,如果還沒有加載的話,圖片的src是放在data-src中。這就是一種預加載的技術。滑動的時候,再激活src。
其次,我想做的是,無論預加載與否,還是瀏覽器是否滑動到圖片對應的位置。微信搜索平台網頁設計的一個便利之處就是在於,它的圖片的真實url是寫在data-src中的。這樣的話,我們就能夠直接讀取data-src中的img地址。
- 但是假如:,它的真實url不是寫在data-src中,我們就要采取selenium的方式滑動整個瀏覽器,然后觸發出圖片的src屬性中值的加載。類似的可以見:http://mp.weixin.qq.com/s?__biz=MzA4OTg1NTg4Nw==&mid=2649071453&idx=1&sn=267082797399b9a10508ebe43ea8a2aa&chksm=8805bdbdbf7234aba7f58308973372a2ae67d1222f4e3ae5166deffe05da4be63f30972b9846&mpshare=1&scene=24&srcid=07153kpPFpe4tyDLziaUuVNC#rd(騰訊動漫圖片的爬取)
最后,我把data-src對應的網址的圖片下載到本地的目錄中,然后建立從圖片url到本地目錄中的圖片文件的映射關系。然后在整個html生成以后。直接替換掉全部的src中的數據,從數據庫中取出對應的文件目錄,然后將本地文件的映射加載進入src中去。這樣的話,就可以實現,爬蟲下來的數據,也能查看到圖片。同之前在網頁中瀏覽的一樣。(這特別類似於瀏覽器的右鍵另存為網頁的時候回生成一個目錄,專門放各種圖片)。
1.3 手動驗證爬取圖片放入到爬取網頁中的可能性
打開以后,查看源代碼:
定位到第一張圖片的位置:
其src是:
我們現在復制網頁源代碼到sublime中,形成一個新的html。
然后將圖片保存為本地的aa.jpeg
接着修改sublime中的本地html中src的為:./aa.jpg
成功了!!!
但是有一個問題:
我直接在瀏覽器中查看網頁源代碼的時候,復制出來的:怎么找都找不到src這個屬性。我剛剛是手動添加的src屬性。
這是因為,瀏覽器中直接查看源碼的方式,顯示的是網頁最初傳回的源碼。那個時候,還沒有觸發js操作,所以只有data-src屬性。所以沒有。但是你在瀏覽器中用右鍵檢查定位的時候,頁面已經刷新了。這是瀏覽器的問題。
我們可以觀察用urllib獲取的網頁數據。看看src屬性的情況。
實驗驗證:真正urllib爬取的也是沒有src的,也是data-src。這就是靜態網頁的弊端。不過,這是微信搜索平台的獨有特點。先加載的都是src。
2 數據庫的設計
weixin_article數據庫
n 第一個collection:用於保存爬取網頁中要加載的圖片。
picture_urlMd5_filepath
包括
{
picture_url:
urlMd5:
filepath:
Count:
}
Count主要是為了記錄該圖片網址被爬取的次數。避免重復爬取。
其中urlMd5可以設置為唯一索引。但是我不打算顯示設置唯一索引。而是在執行插入操作的時候,進行判斷。如果已經有了,則不執行插入操作,count計數加1。如果沒有,再執行插入操作。
n 第二個collection:用於保存爬取的網頁數據
article_urlMd5_filepath
{
article_url:
title:
urlMd5:
filepath:
count:
}
同樣,不顯示設置urlMd5.但是又要保證urlMd5的唯一性。
3 數據庫完整代碼和測試代碼
數據庫接口類
# coding: utf-8 from pymongo import MongoClient class MongodbClient_weixin_article(object): def __init__(self, name, host, port): self.name = name #初始化數據表名,也就是collection的名稱 self.client = MongoClient(host, port) self.db = self.client.weixin_article#使用weixin_article數據庫 def changeTable(self, name): self.name = name def get(self, urlMd5): data = self.db[self.name].find_one({"urlMd5":urlMd5}) return data if data != None else None def put_picture(self,picture_url,urlMd5,filepath): #urlMd5是一個主鍵,我不顯示設置。 condition={"urlMd5":urlMd5} document=self.db[self.name].find_one(condition) if document: #更新count計數 countNum=document['count']+1 document['count']=countNum result=self.db[self.name].update_one(condition,{'$set':document}) print("文檔已經存在!!!准備插入urlMd5:{}的文檔".format(urlMd5)) return None else: document={ "picture_url":picture_url, "urlMd5":urlMd5, "filepath":filepath, "count":1 } result=self.db[self.name].insert(document) print("插入urlMd5:{}的文檔,操作的結果是:{}".format(urlMd5,result)) return result def put_article(self,article_url,urlMd5,title,filepath): #urlMd5是一個主鍵,我不顯示設置。 condition={"urlMd5":urlMd5} document=self.db[self.name].find_one(condition) if document: #更新count計數 countNum=document['count']+1 document['count']=countNum result=self.db[self.name].update_one(condition,{'$set':document}) print("文檔已經存在!!!准備插入urlMd5:{}的文檔".format(urlMd5)) return None else: document={ "article_url":article_url, "urlMd5":urlMd5, "title":title, "filepath":filepath, "count":1 } result=self.db[self.name].insert(document) print("插入urlMd5:{}的文檔,操作的結果是:{}".format(urlMd5,result)) return result def delete(self, urlMd5): result=self.db[self.name].remove({"urlMd5": urlMd5}) print("刪除urlMd5:{}的文檔,操作結果是:{}".format(urlMd5,result)) return result def exists(self, urlMd5): return True if self.db[self.name].find_one({"urlMd5":urlMd5}) != None else False def getNumber(self): return self.db[self.name].count()
測試代碼
# -*- coding: utf-8 -*- """ Created on Fri Jul 20 08:23:55 2018 @author: a """ import MongodbClient_weixin_article import hashlib article_urls=['http://mp.weixin.qq.com/s?src=3×tamp=1532049733&ver=1&signature=0q2qr46UEAp9lSI*yPIN5WoBijEOPhSwZpjbQjQpEiJQyZgy2-5C-L0O3emN-hX0jh79aT3URKtB5s2Se4rL6FuWyfbYPLWnCdDqKNHmRe*TeI4kts0amlyrHgKiK0ixrAP--AHNEt2t-n-9Z7OaxyRTQknx86DkCwPXiKwVY2M=', 'http://mp.weixin.qq.com/s?src=11×tamp=1532049733&ver=1009&signature=egTLXKVBalu7VMZP*77RccSBwkRPNGpWUJqfRs0kBuDfZ8TwbjFoeGuKBQQ4A9bgOpkf4xqhEC2hgRHBYJCyqXwOfyshabHq*F2JjteYIiOyLSLj3eUdK-2WXNqzZHoO&new=1', 'http://mp.weixin.qq.com/s?src=3×tamp=1532049733&ver=1&signature=CsL2-HvpsfVTOhEZM27-LQk5se5W34dAjYuTKkKqNZfBacO55kTVqn*LOBhk6onEQxPMVZ94hWG7WHQ*diKBnEvvzo-0ZN042ly2ORTfEz7T2JLQ3n3L2xe2F3MoEyhpzV0BcVRyMJRGpx3auh8ExL1wkkMj*LTFU5BtpGO6S-0=', 'http://mp.weixin.qq.com/s?src=3×tamp=1532049733&ver=1&signature=VNtNZKptsswWABF3clr725M-y2pg45SZRgqasg8L0wi6r3yzpr43GoAjfpAcIS4LvplqaSRoOqZuMaFBl4z6ILZZpwtj--Bd4V3JBcyiSJ5W9AfsPDRkWGn9G5r148qKxqKW9feJIQ8DDe77rL05xD0QittWApKDOPMiUB8TpkQ=', 'http://mp.weixin.qq.com/s?src=11×tamp=1532049733&ver=1009&signature=O-T3B1RdiF5UUVlreIOsDXInOIb4xRa*W2fo6TH1Bj2NwFZM3ZTe0s6JiR8CCytqCjBbd3OgX7pXGEvh-6ErfIIGiYPMwaIvU*QN3Fjaq0UCehePhKJb67Cohd0rh-U0&new=1', 'http://mp.weixin.qq.com/s?src=3×tamp=1532049733&ver=1&signature=Xt9s5upxnYga-ipwcmVcERz5YqKxwyCSHPCzaicjjqNVwyZ3cO-nPVcDThmlBUlBj9PEU-t9Cm*KwrbYn-2A2719INbLAnViyxGJLTSxXmH1agQOteUr5PYUOi-xjSXDXQvTjySjfnw398n6VE-TqA==', 'http://mp.weixin.qq.com/s?src=3×tamp=1532049733&ver=1&signature=vSyrKJ46Wba0820nEylGfBMVL8Zif6Lj2hiOS49q-46Ik3AihVS1aghAUP4EPf9vmdsD2MJiutX1w7iBavF6TrXLrv6cIwDAK-zpssizzEGmnb6qkJHbFiPLQ87ehmMJzMWDS3Rlkbaze2HbX80W0g==', 'http://mp.weixin.qq.com/s?src=11×tamp=1532049733&ver=1009&signature=5*fJWC70b49HJpfvLnE0vGjQvGjtitjna9ObOpL6i2QAzR9wZdRoaWY0d7DxSEbxmo1LEDYF7Zz0MZyh8jd1Zzh4jIDj7XgFFdPRaERg4mR9yaoCWak1lHPAZu3q3bCs&new=1', 'http://mp.weixin.qq.com/s?src=3×tamp=1532049733&ver=1&signature=n5Yd0nWrycz23WZAj-I3tCi0LmoRs4PLgtcoLoK1bmMgZJcxF*f*rIOt9z3UobXHhvjVpIbbXD1ljjMFCvW*V-XA0eL74LgM4Xdox-9cd58m0qmUObfvlB6Yp7J6hIZMtoY-9Ay3aFerB7-iBDi-fQ==', 'http://mp.weixin.qq.com/s?src=11×tamp=1532049733&ver=1009&signature=wv02IRQ65jrVpoaBW9HHvpWsHXOf61ageled59cpyOzTdJ1w4tjY8aQ-JvgYqfYRlF7YlKiyIrXLbBEqc-9YKkxe8weaG8zOGgfykYEam9BoKWWqI65SMAIoRGj-JNNh&new=1'] db=MongodbClient_weixin_article.MongodbClient_weixin_article("article_urlMd5_filepath","localhost",27017) #db.changeTable("picture_urlMd5_filepath") for i in range(len(article_urls)): m = hashlib.md5() url=article_urls[i].encode() m.update(url) urlMd5=m.hexdigest() title="love you baby" filepath="./測試地址" db.put_article(article_urls[i],urlMd5,title,filepath) print (db.exists("b6c825349ce9c94d1d56c3c628bfc223")) print (db.get("b6c825349ce9c94d1d56c3c628bfc223")) print (db.getNumber()) for i in range(len(article_urls)): m = hashlib.md5() url=article_urls[i].encode() m.update(url) urlMd5=m.hexdigest() title="love you baby" filepath="./測試地址" db.put_article(article_urls[i],urlMd5,title,filepath) for i in range(len(article_urls)): m = hashlib.md5() url=article_urls[i].encode() m.update(url) urlMd5=m.hexdigest() filepath="./測試地址" db.delete(urlMd5)
runfile('G:/精通python網絡爬蟲/針對目標網站的爬蟲/測試url和md5映射的mongodb數據庫.py', wdir='G:/精通python網絡爬蟲/針對目標網站的爬蟲') 插入urlMd5:4dc6c2896ee7bd96dcc27b561eafb709的文檔,操作的結果是:5b514560b61e0913b060af49 插入urlMd5:b6c825349ce9c94d1d56c3c628bfc223的文檔,操作的結果是:5b514560b61e0913b060af4a 插入urlMd5:18a5ee6e623b3b76d96e6cec2e2db1ad的文檔,操作的結果是:5b514560b61e0913b060af4b 插入urlMd5:f31d114c5ea5e6d37adbc7048531fc76的文檔,操作的結果是:5b514560b61e0913b060af4c 插入urlMd5:d1a8faad9d00bbf2966dc3db75d6f128的文檔,操作的結果是:5b514560b61e0913b060af4d 插入urlMd5:731b7e7074c969ffd36685300abe7b0e的文檔,操作的結果是:5b514560b61e0913b060af4e 插入urlMd5:011821ee4b366a7a396ccc6958a091d3的文檔,操作的結果是:5b514560b61e0913b060af4f 插入urlMd5:ea185627b10b0b4b66fe2da7bcec3974的文檔,操作的結果是:5b514560b61e0913b060af50 插入urlMd5:b0edcbdb3d4171aea30f1c28e2db10ea的文檔,操作的結果是:5b514560b61e0913b060af51 插入urlMd5:d4759df2c6c3c4973db3d4ddcd37bed2的文檔,操作的結果是:5b514560b61e0913b060af52 True {'_id': ObjectId('5b514560b61e0913b060af4a'), 'article_url': 'http://mp.weixin.qq.com/s?src=11×tamp=1532049733&ver=1009&signature=egTLXKVBalu7VMZP*77RccSBwkRPNGpWUJqfRs0kBuDfZ8TwbjFoeGuKBQQ4A9bgOpkf4xqhEC2hgRHBYJCyqXwOfyshabHq*F2JjteYIiOyLSLj3eUdK-2WXNqzZHoO&new=1', 'urlMd5': 'b6c825349ce9c94d1d56c3c628bfc223', 'title': 'love you baby', 'filepath': './測試地址', 'count': 1} 10 文檔已經存在!!!准備插入urlMd5:4dc6c2896ee7bd96dcc27b561eafb709的文檔 文檔已經存在!!!准備插入urlMd5:b6c825349ce9c94d1d56c3c628bfc223的文檔 文檔已經存在!!!准備插入urlMd5:18a5ee6e623b3b76d96e6cec2e2db1ad的文檔 文檔已經存在!!!准備插入urlMd5:f31d114c5ea5e6d37adbc7048531fc76的文檔 文檔已經存在!!!准備插入urlMd5:d1a8faad9d00bbf2966dc3db75d6f128的文檔 文檔已經存在!!!准備插入urlMd5:731b7e7074c969ffd36685300abe7b0e的文檔 文檔已經存在!!!准備插入urlMd5:011821ee4b366a7a396ccc6958a091d3的文檔 文檔已經存在!!!准備插入urlMd5:ea185627b10b0b4b66fe2da7bcec3974的文檔 文檔已經存在!!!准備插入urlMd5:b0edcbdb3d4171aea30f1c28e2db10ea的文檔 文檔已經存在!!!准備插入urlMd5:d4759df2c6c3c4973db3d4ddcd37bed2的文檔 刪除urlMd5:4dc6c2896ee7bd96dcc27b561eafb709的文檔,操作結果是:{'n': 1, 'ok': 1.0} 刪除urlMd5:b6c825349ce9c94d1d56c3c628bfc223的文檔,操作結果是:{'n': 1, 'ok': 1.0} 刪除urlMd5:18a5ee6e623b3b76d96e6cec2e2db1ad的文檔,操作結果是:{'n': 1, 'ok': 1.0} 刪除urlMd5:f31d114c5ea5e6d37adbc7048531fc76的文檔,操作結果是:{'n': 1, 'ok': 1.0} 刪除urlMd5:d1a8faad9d00bbf2966dc3db75d6f128的文檔,操作結果是:{'n': 1, 'ok': 1.0} 刪除urlMd5:731b7e7074c969ffd36685300abe7b0e的文檔,操作結果是:{'n': 1, 'ok': 1.0} 刪除urlMd5:011821ee4b366a7a396ccc6958a091d3的文檔,操作結果是:{'n': 1, 'ok': 1.0} 刪除urlMd5:ea185627b10b0b4b66fe2da7bcec3974的文檔,操作結果是:{'n': 1, 'ok': 1.0} 刪除urlMd5:b0edcbdb3d4171aea30f1c28e2db10ea的文檔,操作結果是:{'n': 1, 'ok': 1.0} 刪除urlMd5:d4759df2c6c3c4973db3d4ddcd37bed2的文檔,操作結果是:{'n': 1, 'ok': 1.0}
斷點下在刪除操作前: