爬蟲——實戰完整版

抿嘴脣發表於2018-09-25

mongodb操作

 1 import pymongo
 2 
 3 #連線資料庫例項(連線資料庫)---》獲取相應資料庫---》獲取相應collection集合(表)
 4 client = pymongo.MongoClient(host=`localhost`,port=27017)
 5 
 6 db = client.test        #也可用字典形式操作,如下
 7 # db = client["test"]
 8 
 9 collection  = db.students  #也可用字典形式操作,如下
10 # collection = db["students"]
11 
12 student1 = {
13     `id`:`001`,
14     `name`:`haha`,
15     `age`:20,
16     `gender`:`male`
17 }
18 student2 = {
19     `id`: `002`,
20     `name`: `Mike`,
21     `age`: 41,
22     `gender`: `male`
23 }
24 #--------------------------------------------------------------------------
25         #插入 insert into students(...) values(`002`,...)
26         #若不指定 _id 欄位,系統預設會生成一個ObjectId
27         #可插入一條或多條資料(列表形式),python3不推薦使用insert
28 # collection.insert([student1,student2])
29 # collection.insert(student1)
30 
31         #官方推薦,分開使用,返回值不是ObjectId,而是InsertOneResult物件,我們可以呼叫其inserted_id屬性獲取_id。
32 # result = collection.insert_one(student2)
33 # print(result)
34 # print(result.inserted_id)
35 
36 # result = collection.insert_many([student1,student2])
37 # print(result)
38 # print(result.inserted_ids)
39 
40 #------------------------------------------------------------------
41         #查詢 select * from students where id=002
42         #查詢條件使用字典,可使用多欄位,find是多條查詢
43 # result_find = collection.find({"name":"lijingbo","age":20})
44 # print(result_find.next())   #返回一個遊標,遊標相當於迭代器,可使用next()獲取一條結果,或者使用迴圈遍歷等,遍歷結果是字典
45         #find_one:單個查詢,返回字典型別
46 # result = collection.find_one({`age`:20})
47 # print(result,type(result))
48         #結合關係符進行查詢:$gt,$lt,$gte,$lte,$ne,$in,$nin
49 # result = collection.find({`age`:{`$gt`:18}})
50 # result = collection.find({`age`:{`$in`:[18,41]}})
51         #結合特殊符號查詢:$regex
52 # result = collection.find({`name`:{`$regex`:`^M.*`}})  #正則
53 # result = collection.find({`name`:{`$exists`:True}})     #查詢含有name屬性的
54 # result = collection.find({`age`:{`$mod`:[5,0]}})        #求模,對5取餘=0
55 # result = collection.find({`$where`:`obj.age==20`})       #查詢age為20的,obj是自身
56 # result = collection.find({`age`:20}).count()                #統計
57 # result = collection.find().sort(`age`,pymongo.ASCENDING)      #按照指定欄位升序排列
58 # result = collection.find().sort(`age`,pymongo.DESCENDING)     #按照指定欄位升序排列
59 # result = collection.find().sort(`age`,pymongo.DESCENDING).skip(2)     #按照指定欄位升序排列,偏移2個(就是把最前面兩個跳過去了)
60 # result = collection.find().sort(`age`,pymongo.DESCENDING).skip(2).limit(5)    #限制得到5
61 # print(result)
62 # for r in result:
63 #     print(r[`name`],r[`age`])
64 
65 #----------------------------------------------------------
66         #更新 update students set name=haha where id=001
67         #引數1:查詢條件(字典);引數2:更新值(字典,鍵:`$set`,值:字典【也可直接使用外部字典】)
68         #其他:upsert預設為False,為True時——若更新的原資料不存在,則插入資料
69                 #multi——預設為False只更新查詢到的第一條資料,為True時:更新全部查詢到的資料
70         # $set:是mongodb內建函式,覆蓋原始資料
71 # collection.update({"id":"001"},{`$set`:{`age`:34}},upsert=True,multi=True)
72 # print(collection.find().next())
73         #上面的官方也不推薦,可以使用下面的
74 # result = collection.update_one({`name`:`haha`},{`$set`:{`age`:18}})
75 # result = collection.update_many({`name`:`haha`},{`$set`:{`age`:18}})
76 # print(result)   #只修改一條資料,若該資料不修改就和修改條件一樣了,那有可能修改數為0
77 # print(result.matched_count,result.modified_count)
78 
79 
80 #-----------------------------------------------------
81         #刪除,remove方法官方不推薦
82 # collection.remove({"id":"001"},justOne=1)
83 # result = collection.delete_one({`name`:`Mike`})
84 # result = collection.delete_many({`name`:`Mike`})
85 # print(result)
86 # print(result.deleted_count)
87 
88 #---------------------------------------------------
89         #組合方法
90 # result = collection.find_one_and_delete({`name`:`haha`})
91 # result = collection.find_one_and_update({`name`:`haha`},{`$set`:{`age`:45}})
92 # result = collection.find_one_and_replace({`name`:`haha`})
93 # print(result)

 

MongoCache

將資料以字典的特性儲存快取到mongodb資料庫

匯入類庫

import pickle,zlib  #物件序列化    壓縮資料
from datetime import datetime,timedelta     #設定快取超時間間隔
from pymongo import MongoClient
from bson.binary import Binary      #MongoDB儲存二進位制的型別

建立MongoCache類

  • 初始化init
    • 連線mongodb資料庫
    • 連線資料庫cache例項(沒有則建立)
    • 連線集合webpage(沒有則建立)
    • 建立timestamp索引,設定超時時間為30天
  • 重寫__setitem__
    • 資料經過pickle序列化
    • zlib壓縮
    • 經Binary轉化為mongodb需要的格式
    • 新增格林威治時間
    • 網址為鍵_id,結果為值,存入mongodb

使用下載的url(路由)作為key,存入系統預設的_id欄位,更新資料庫,若存在則更新,不存在則插入,_id唯一就可實現爬取的資料去重

用字典的形式向資料庫新增一條快取(資料)

  • 重寫__getitem__

    • 將快取資料按照item作為key取出(key仍然是下載的url)
    • 根據_id(url)查詢(find_one)結果
    • 解壓縮,反序列化
  • 重寫__contains__

    • 當呼叫in,not in ,會自動呼叫該方法判斷連結對應網址是否在資料庫中
    • 可通過字典的查詢方式__getitem__直接查詢(self[item])
    • 該函式返回布林值
  • 方法clear

    • 清空該集合中的資料
       1 import pickle,zlib  #物件序列化    壓縮資料
       2 from datetime import datetime,timedelta     #設定快取超時間間隔
       3 from pymongo import MongoClient
       4 from bson.binary import Binary      #MongoDB儲存二進位制的型別
       5 from http_ljb.tiebaspider import TiebaSpider
       6 from http_ljb.qiushispider import QiushiSpider
       7 
       8 class MongoCache:
       9     def __init__(self,client=None,expires=timedelta(days=30)):
      10         ```
      11         初始化函式
      12         :param client: 資料庫連線(資料庫例項)
      13         :param expires: 超時時間
      14         ```
      15         self.client = MongoClient(`localhost`,27017)
      16         self.db = self.client.cache     #建立名為cache的資料庫
      17         web_page = self.db.webpage      #建立集合webpage並賦值給變數
      18         #建立timestamp索引,設定超時時間為30天,total_seconds會將days轉為秒
      19         self.db.webpage.create_index(`timestamp`,expireAfterSeconds=expires.total_seconds())
      20 
      21     def __setitem__(self, key, value):
      22         ```
      23         用字典的形式向資料庫新增一條快取(資料)
      24         :param key: 快取的鍵
      25         :param value: 快取的值
      26         :return:
      27         ```
      28         #資料---》pickle序列化---》zlib壓縮---》Binary轉化為mondodb需要的格式,使用格林威治時間
      29         record = {`result`:Binary(zlib.compress(pickle.dumps(value))),`timestamp`:datetime.utcnow()}
      30         #使用下載的url(路由)作為key,存入系統預設的_id欄位,更新資料庫,若存在則更新,不存在則插入,_id唯一就可實現爬取的資料去重
      31         self.db.webpage.update({`_id`:key},{`$set`:record},upsert=True)
      32 
      33     def __getitem__(self, item):
      34         ```
      35         將快取資料按照item作為key取出(key仍然是下載的url)
      36         :param item:鍵
      37         :return:
      38         ```
      39         record = self.db.webpage.find_one({`_id`:item}) #查詢出來就不是Binary了,不用進行轉化
      40         if record:
      41             return pickle.loads(zlib.decompress(record[`result`])) #解壓縮,反序列化
      42         else:
      43             raise KeyError(item + `does not exist`)     #查詢不到就丟擲鍵錯誤異常
      44 
      45     def __contains__(self, item):
      46         ```
      47         當呼叫in,not in ,會自動呼叫該方法判斷連結對應網址是否在資料庫中
      48         :param item: 下載的url連結(路由)
      49         :return:
      50         ```
      51         try:
      52             self[item]      #這一步會呼叫__getitem__,找不到__getitem__會丟擲異常,在這裡進行捕獲異常只返回False,否則返回True
      53         except KeyError:
      54             return False
      55         else:
      56             return True
      57 
      58     def clear(self):
      59         ```
      60         清空該集合中的資料
      61         :return:
      62         ```
      63         self.db.webpage.drop()

       

爬取例項

呼叫貼吧爬取程式碼和百科爬取程式碼,使用mongodb儲存爬取資料

 

  • 匯入爬取類
  • 建立新類並繼承自爬取類
  • 重寫儲存方法
    • 建立MongoCache物件
    • 網址為鍵,資料為值,以字典形式存入mongodb
  • 重寫run方法
    • 在儲存時,需多傳一個網址引數(為了在儲存方法中對應儲存)
        1 import pickle,zlib  #物件序列化    壓縮資料
        2 from datetime import datetime,timedelta     #設定快取超時間間隔
        3 from pymongo import MongoClient
        4 from bson.binary import Binary      #MongoDB儲存二進位制的型別
        5 from http_ljb.tiebaspider import TiebaSpider
        6 from http_ljb.qiushispider import QiushiSpider
        7 
        8 class MongoCache:
        9     def __init__(self,client=None,expires=timedelta(days=30)):
       10         ```
       11         初始化函式
       12         :param client: 資料庫連線(資料庫例項)
       13         :param expires: 超時時間
       14         ```
       15         self.client = MongoClient(`localhost`,27017)
       16         self.db = self.client.cache     #建立名為cache的資料庫
       17         web_page = self.db.webpage      #建立集合webpage並賦值給變數
       18         #建立timestamp索引,設定超時時間為30天,total_seconds會將days轉為秒
       19         self.db.webpage.create_index(`timestamp`,expireAfterSeconds=expires.total_seconds())
       20 
       21     def __setitem__(self, key, value):
       22         ```
       23         用字典的形式向資料庫新增一條快取(資料)
       24         :param key: 快取的鍵
       25         :param value: 快取的值
       26         :return:
       27         ```
       28         #資料---》pickle序列化---》zlib壓縮---》Binary轉化為mondodb需要的格式,使用格林威治時間
       29         record = {`result`:Binary(zlib.compress(pickle.dumps(value))),`timestamp`:datetime.utcnow()}
       30         #使用下載的url(路由)作為key,存入系統預設的_id欄位,更新資料庫,若存在則更新,不存在則插入,_id唯一就可實現爬取的資料去重
       31         self.db.webpage.update({`_id`:key},{`$set`:record},upsert=True)
       32 
       33     def __getitem__(self, item):
       34         ```
       35         將快取資料按照item作為key取出(key仍然是下載的url)
       36         :param item:鍵
       37         :return:
       38         ```
       39         record = self.db.webpage.find_one({`_id`:item}) #查詢出來就不是Binary了,不用進行轉化
       40         if record:
       41             return pickle.loads(zlib.decompress(record[`result`])) #解壓縮,反序列化
       42         else:
       43             raise KeyError(item + `does not exist`)     #查詢不到就丟擲鍵錯誤異常
       44 
       45     def __contains__(self, item):
       46         ```
       47         當呼叫in,not in ,會自動呼叫該方法判斷連結對應網址是否在資料庫中
       48         :param item: 下載的url連結(路由)
       49         :return:
       50         ```
       51         try:
       52             self[item]      #這一步會呼叫__getitem__,找不到__getitem__會丟擲異常,在這裡進行捕獲異常只返回False,否則返回True
       53         except KeyError:
       54             return False
       55         else:
       56             return True
       57 
       58     def clear(self):
       59         ```
       60         清空該集合中的資料
       61         :return:
       62         ```
       63         self.db.webpage.drop()
       64 
       65 class TiebaMongo(TiebaSpider):
       66     def save_result(self, result,url_str):
       67         """
       68         重寫父類的該方法,將資料儲存到資料庫
       69         :param result:
       70         :param url_str:
       71         :return:
       72         """
       73         mc = MongoCache()
       74         mc[url_str] = result
       75 
       76     def run(self):
       77         url_lists = self.make_url()
       78         for url_str in url_lists:
       79             result_str = self.download_url(url_str)
       80             self.save_result(result=result_str,url_str=url_str)
       81 
       82 # class QiushiMongo(QiushiSpider):
       83 #     def save_result(self, result,url_str):
       84 #         mc = MongoCache()
       85 #         mc[url_str] = result
       86 #
       87 #     def run(self):
       88 #         url_lists = self.make_url()
       89 #         for url_str in url_lists:
       90 #             result_str = self.download_url(url_str)
       91 #             self.save_result(result=result_str,url_str=url_str)
       92 
       93 # if __name__ == `__main__`:
       94         #爬取貼吧並存到MongoDB
       95     # test = TiebaMongo(`lol`)
       96     # test.run()
       97         #爬取糗事並存到MongoDB
       98     # qiushi = QiushiMongo()
       99     # qiushi.run()
      100         #查詢MongoDB
      101     # mc = MongoCache()
      102     # print(mc[`https://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=2`])
      103     # print(`https://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=3` in mc)
      104     # cha = MongoCache()
      105     # print(cha[test.url_base])
      106     # print(mc["https://www.qiushibaike.com/8hr/page/2/"])

       

 

相關文章