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。

但是有一個問題就是,不同的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 手動驗證爬取圖片放入到爬取網頁中的可能性

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}

斷點下在刪除操作前:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM