7 爬蟲爬取網頁文章(保留圖片和文本順序,原封不動)的數據庫設計,且避免重複抓取

1 設計思考

1.1 關於爬取文章存儲的思考

  • 第一,文章要抓取到本地;
  • 第二,查詢文件大小,若是文件過大,超出多少M,則新建一個主題文件好比:file="./"+"微信文章_"+key+編號+".html"。我從多個html中提取信息,而後寫入到同一個html中。(能夠參見精通python網絡爬蟲的第六章中的爬取微信搜索平臺。可是本文遠比它複雜)
  • 關於mongodb數據庫的設計:首先是:文章的url,標題,而後是md5編碼(用來避免重複抓取),接着是,文章在本地的存儲位置。就的file="./"+"微信文章_"+key+編號+".html"文件,而後是計數count。由於使用微信搜索平臺的時候,不一樣的關鍵詞搜索,返回的結果中可能存在重複的文章,避免重複抓取。

其實,我也想過,以不一樣的key去微信搜索平臺進行搜索,將返回的文章,存入到mongodb數據庫不一樣的collection中。而後,下次以該key去抓取文章的時候,要避免重複抓取,就能夠去檢索mongodb數據庫,該key對應的collection。html

可是有一個問題就是,不一樣的key進行搜索,好比:「如何追漂亮妹子」,」如何追漂亮女生」,這兩個搜索的有重複的文章。用上面的方式,相同url下的文章會放入不一樣的collection中。python

雖然,本着樸實的態度,不一樣的key進行搜索獲得的文件應該寫入到不一樣數據庫中,以表示這個key的搜索結果。mongodb

可是,本着爲我負責的態度,(我不想看重複的信息),不一樣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 手動驗證爬取圖片放入到爬取網頁中的可能性

https://mp.weixin.qq.com/s?src=11&timestamp=1532009093&ver=1008&signature=S3l6-eHWrNfztFcZmVbnmVG59YtsttDdT3zhJDgCDPKlErs2EswLNeqKnUd2lQ5oXeOjOlqCQ5r9PO1R906niAvZD1fghqDFQkcoTJXwf5ow87m101AgxYDWjeLuGDdS&new=1

打開之後,查看源代碼:

定位到第一張圖片的位置:

其src是:

https://mmbiz.qpic.cn/mmbiz_jpg/kDtDibeZ5VHT6GHGSdR0R1k4UqV71AQiajvNB1jykBRcg1Q1zOnFVpTOwXcPAHiciaaGaIHSn0vuUce3cCA5kpeQTw/640?wx_fmt=jpeg

咱們如今複製網頁源代碼到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&timestamp=1532049733&ver=1&signature=0q2qr46UEAp9lSI*yPIN5WoBijEOPhSwZpjbQjQpEiJQyZgy2-5C-L0O3emN-hX0jh79aT3URKtB5s2Se4rL6FuWyfbYPLWnCdDqKNHmRe*TeI4kts0amlyrHgKiK0ixrAP--AHNEt2t-n-9Z7OaxyRTQknx86DkCwPXiKwVY2M=', 'http://mp.weixin.qq.com/s?src=11&timestamp=1532049733&ver=1009&signature=egTLXKVBalu7VMZP*77RccSBwkRPNGpWUJqfRs0kBuDfZ8TwbjFoeGuKBQQ4A9bgOpkf4xqhEC2hgRHBYJCyqXwOfyshabHq*F2JjteYIiOyLSLj3eUdK-2WXNqzZHoO&new=1', 'http://mp.weixin.qq.com/s?src=3&timestamp=1532049733&ver=1&signature=CsL2-HvpsfVTOhEZM27-LQk5se5W34dAjYuTKkKqNZfBacO55kTVqn*LOBhk6onEQxPMVZ94hWG7WHQ*diKBnEvvzo-0ZN042ly2ORTfEz7T2JLQ3n3L2xe2F3MoEyhpzV0BcVRyMJRGpx3auh8ExL1wkkMj*LTFU5BtpGO6S-0=', 'http://mp.weixin.qq.com/s?src=3&timestamp=1532049733&ver=1&signature=VNtNZKptsswWABF3clr725M-y2pg45SZRgqasg8L0wi6r3yzpr43GoAjfpAcIS4LvplqaSRoOqZuMaFBl4z6ILZZpwtj--Bd4V3JBcyiSJ5W9AfsPDRkWGn9G5r148qKxqKW9feJIQ8DDe77rL05xD0QittWApKDOPMiUB8TpkQ=', 'http://mp.weixin.qq.com/s?src=11&timestamp=1532049733&ver=1009&signature=O-T3B1RdiF5UUVlreIOsDXInOIb4xRa*W2fo6TH1Bj2NwFZM3ZTe0s6JiR8CCytqCjBbd3OgX7pXGEvh-6ErfIIGiYPMwaIvU*QN3Fjaq0UCehePhKJb67Cohd0rh-U0&new=1', 'http://mp.weixin.qq.com/s?src=3&timestamp=1532049733&ver=1&signature=Xt9s5upxnYga-ipwcmVcERz5YqKxwyCSHPCzaicjjqNVwyZ3cO-nPVcDThmlBUlBj9PEU-t9Cm*KwrbYn-2A2719INbLAnViyxGJLTSxXmH1agQOteUr5PYUOi-xjSXDXQvTjySjfnw398n6VE-TqA==', 'http://mp.weixin.qq.com/s?src=3&timestamp=1532049733&ver=1&signature=vSyrKJ46Wba0820nEylGfBMVL8Zif6Lj2hiOS49q-46Ik3AihVS1aghAUP4EPf9vmdsD2MJiutX1w7iBavF6TrXLrv6cIwDAK-zpssizzEGmnb6qkJHbFiPLQ87ehmMJzMWDS3Rlkbaze2HbX80W0g==', 'http://mp.weixin.qq.com/s?src=11&timestamp=1532049733&ver=1009&signature=5*fJWC70b49HJpfvLnE0vGjQvGjtitjna9ObOpL6i2QAzR9wZdRoaWY0d7DxSEbxmo1LEDYF7Zz0MZyh8jd1Zzh4jIDj7XgFFdPRaERg4mR9yaoCWak1lHPAZu3q3bCs&new=1', 'http://mp.weixin.qq.com/s?src=3&timestamp=1532049733&ver=1&signature=n5Yd0nWrycz23WZAj-I3tCi0LmoRs4PLgtcoLoK1bmMgZJcxF*f*rIOt9z3UobXHhvjVpIbbXD1ljjMFCvW*V-XA0eL74LgM4Xdox-9cd58m0qmUObfvlB6Yp7J6hIZMtoY-9Ay3aFerB7-iBDi-fQ==', 'http://mp.weixin.qq.com/s?src=11&timestamp=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&timestamp=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}

斷點下在刪除操做前:

相關文章
相關標籤/搜索