Python爬蟲——爬取豆瓣讀書信息并存入數(shù)據(jù)庫

這兩天爬了豆瓣讀書的十萬條左右的書目信息,用時(shí)將近一天,現(xiàn)在趁著這個(gè)空閑把代碼總結(jié)一下,還是菜鳥,都是用的最簡(jiǎn)單最笨的方法,還請(qǐng)路過的大神不吝賜教。
第一步,先看一下我們需要的庫:

import requests                       #用來請(qǐng)求網(wǎng)頁
from bs4 import BeautifulSoup         #解析網(wǎng)頁
import time          #設(shè)置延時(shí)時(shí)間,防止爬取過于頻繁被封IP號(hào)
import re            #正則表達(dá)式庫
import pymysql       #由于爬取的數(shù)據(jù)太多,我們要把他存入MySQL數(shù)據(jù)庫中,這個(gè)庫用于連接數(shù)據(jù)庫
import random        #這個(gè)庫里用到了產(chǎn)生隨機(jī)數(shù)的randint函數(shù),和上面的time搭配,使爬取間隔時(shí)間隨機(jī)

這個(gè)是豆瓣的網(wǎng)址:https://book.douban.com/tag/?view=type&icn=index-sorttags-all
我們要從這里獲取所有分類的標(biāo)簽鏈接,進(jìn)一步去爬取里面的信息,代碼先貼上來:

import requests
from bs4 import BeautifulSoup       #導(dǎo)入庫

url="https://book.douban.com/tag/?icn=index-nav"
wb_data=requests.get(url)                #請(qǐng)求網(wǎng)址
soup=BeautifulSoup(wb_data.text,"lxml")  #解析網(wǎng)頁信息
tags=soup.select("#content > div > div.article > div > div > table > tbody > tr > td > a")
     #根據(jù)CSS路徑查找標(biāo)簽信息,CSS路徑獲取方法,右鍵-檢查-copy selector,tags返回的是一個(gè)列表
for tag in tags:    
       tag=tag.get_text()    #將列表中的每一個(gè)標(biāo)簽信息提取出來
       helf="https://book.douban.com/tag/"   
          #觀察一下豆瓣的網(wǎng)址,基本都是這部分加上標(biāo)簽信息,所以我們要組裝網(wǎng)址,用于爬取標(biāo)簽詳情頁
       url=helf+str(tag)  
       print(url)    #網(wǎng)址組裝完畢,輸出

以上我們便爬取了所有標(biāo)簽下的網(wǎng)址,我們將這個(gè)文件命名為channel,并在channel中創(chuàng)建一個(gè)channel字符串,放上我們所有爬取的網(wǎng)址信息,等下爬取詳情頁的時(shí)候直接從這里提取鏈接就好了,如下:

channel='''   
      https://book.douban.com/tag/小說     
      https://book.douban.com/tag/外國(guó)文學(xué)    
      https://book.douban.com/tag/文學(xué)    
      https://book.douban.com/tag/隨筆     
      https://book.douban.com/tag/中國(guó)文學(xué)    
      https://book.douban.com/tag/經(jīng)典    
      https://book.douban.com/tag/日本文學(xué)    
      https://book.douban.com/tag/散文    
      https://book.douban.com/tag/村上春樹    
      https://book.douban.com/tag/詩歌    
      https://book.douban.com/tag/童話    
      https://book.douban.com/tag/雜文    
      https://book.douban.com/tag/王小波    
      https://book.douban.com/tag/兒童文學(xué)    
      https://book.douban.com/tag/古典文學(xué)    
      https://book.douban.com/tag/張愛玲    
      https://book.douban.com/tag/名著    
      https://book.douban.com/tag/余華    
      https://book.douban.com/tag/當(dāng)代文學(xué)    
      https://book.douban.com/tag/錢鐘書    
      https://book.douban.com/tag/魯迅    
      https://book.douban.com/tag/外國(guó)名著    
      https://book.douban.com/tag/詩詞    
      https://book.douban.com/tag/茨威格    
      https://book.douban.com/tag/米蘭·昆德拉    
      https://book.douban.com/tag/杜拉斯    
      https://book.douban.com/tag/港臺(tái)    
      https://book.douban.com/tag/漫畫    
      https://book.douban.com/tag/繪本    
      https://book.douban.com/tag/推理    
      https://book.douban.com/tag/青春    
      https://book.douban.com/tag/言情    
      https://book.douban.com/tag/科幻    
      https://book.douban.com/tag/東野圭吾    
      https://book.douban.com/tag/懸疑    
      https://book.douban.com/tag/武俠    
      https://book.douban.com/tag/奇幻    
      https://book.douban.com/tag/韓寒    
      https://book.douban.com/tag/日本漫畫    
      https://book.douban.com/tag/耽美    
      https://book.douban.com/tag/亦舒    
      https://book.douban.com/tag/三毛    
      https://book.douban.com/tag/安妮寶貝    
      https://book.douban.com/tag/網(wǎng)絡(luò)小說    
      https://book.douban.com/tag/推理小說    
      https://book.douban.com/tag/郭敬明    
      https://book.douban.com/tag/穿越    
      https://book.douban.com/tag/金庸    
      https://book.douban.com/tag/輕小說    
      https://book.douban.com/tag/阿加莎·克里斯蒂    
      https://book.douban.com/tag/幾米    
      https://book.douban.com/tag/魔幻    
      https://book.douban.com/tag/張小嫻    
      https://book.douban.com/tag/幾米    
      https://book.douban.com/tag/青春文學(xué)    
      https://book.douban.com/tag/科幻小說    
      https://book.douban.com/tag/J.K.羅琳    
      https://book.douban.com/tag/高木直子    
      https://book.douban.com/tag/古龍    
      https://book.douban.com/tag/滄月    
      https://book.douban.com/tag/落落    
      https://book.douban.com/tag/張悅?cè)?   
      https://book.douban.com/tag/蔡康永    
      https://book.douban.com/tag/歷史    
      https://book.douban.com/tag/心理學(xué)    
      https://book.douban.com/tag/哲學(xué)    
      https://book.douban.com/tag/傳記    
      https://book.douban.com/tag/文化    
      https://book.douban.com/tag/社會(huì)學(xué)    
      https://book.douban.com/tag/藝術(shù)    
      https://book.douban.com/tag/設(shè)計(jì)    
      https://book.douban.com/tag/政治    
      https://book.douban.com/tag/社會(huì)    
      https://book.douban.com/tag/建筑    
      https://book.douban.com/tag/宗教    
      https://book.douban.com/tag/電影    
      https://book.douban.com/tag/數(shù)學(xué)    
      https://book.douban.com/tag/政治學(xué)    
      https://book.douban.com/tag/回憶錄    
      https://book.douban.com/tag/思想    
      https://book.douban.com/tag/中國(guó)歷史    
      https://book.douban.com/tag/國(guó)學(xué)    
      https://book.douban.com/tag/音樂    
      https://book.douban.com/tag/人文    
      https://book.douban.com/tag/人物傳記    
      https://book.douban.com/tag/戲劇          
      https://book.douban.com/tag/生活    
      https://book.douban.com/tag/成長(zhǎng)    
      https://book.douban.com/tag/勵(lì)志    
      https://book.douban.com/tag/心理     
      https://book.douban.com/tag/攝影    
      https://book.douban.com/tag/女性    
      https://book.douban.com/tag/職場(chǎng)    
      https://book.douban.com/tag/美食    
      https://book.douban.com/tag/教育    
      https://book.douban.com/tag/游記    
      https://book.douban.com/tag/靈修    
      https://book.douban.com/tag/健康    
      https://book.douban.com/tag/情感    
      https://book.douban.com/tag/手工    
      https://book.douban.com/tag/養(yǎng)生    
      https://book.douban.com/tag/兩性    
      https://book.douban.com/tag/人際關(guān)系    
      https://book.douban.com/tag/家居    
      https://book.douban.com/tag/自助游    
      https://book.douban.com/tag/經(jīng)濟(jì)學(xué)    
      https://book.douban.com/tag/管理    
      https://book.douban.com/tag/經(jīng)濟(jì)    
      https://book.douban.com/tag/商業(yè)    
      https://book.douban.com/tag/金融    
      https://book.douban.com/tag/投資    
      https://book.douban.com/tag/營(yíng)銷    
      https://book.douban.com/tag/創(chuàng)業(yè)    
      https://book.douban.com/tag/理財(cái)    
      https://book.douban.com/tag/廣告       
      https://book.douban.com/tag/股票    
      https://book.douban.com/tag/企業(yè)史    
      https://book.douban.com/tag/策劃    
      https://book.douban.com/tag/科普    
      https://book.douban.com/tag/互聯(lián)網(wǎng)    
      https://book.douban.com/tag/編程    
      https://book.douban.com/tag/科學(xué)    
      https://book.douban.com/tag/交互設(shè)計(jì)    
      https://book.douban.com/tag/用戶體驗(yàn)    
      https://book.douban.com/tag/算法    
      https://book.douban.com/tag/web    
      https://book.douban.com/tag/科技    
      https://book.douban.com/tag/UE    
      https://book.douban.com/tag/通信    
      https://book.douban.com/tag/交互         
      https://book.douban.com/tag/UCD    
      https://book.douban.com/tag/神經(jīng)網(wǎng)絡(luò)    
      https://book.douban.com/tag/程序              
     '''

現(xiàn)在,我們開始第二個(gè)程序。

QQ圖片20160915233329.png

標(biāo)簽頁下每一個(gè)圖片的信息基本都是這樣的,我們可以直接從這里提取到標(biāo)題,作者,出版社,出版時(shí)間,價(jià)格,評(píng)價(jià)人數(shù),以及評(píng)分等信息(有些外國(guó)作品還會(huì)有譯者信息),提取方法與提取標(biāo)簽類似,也是根據(jù)CSS路徑提取。
我們先用一個(gè)網(wǎng)址來實(shí)驗(yàn)爬?。?/p>

url="https://book.douban.com/tag/科技"
wb_data = requests.get(url)
soup = BeautifulSoup(wb_data.text.encode("utf-8"), "lxml")
tag=url.split("?")[0].split("/")[-1]    #從鏈接里面提取標(biāo)簽信息,方便存儲(chǔ)
detils=soup.select("#subject_list > ul > li > div.info > div.pub")  #抓取作者,出版社信息,稍后我們用spite()函數(shù)再將他們分離出來
scors=soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.rating_nums")   #抓取評(píng)分信息
persons=soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.pl")    #評(píng)價(jià)人數(shù)
titles=soup.select("#subject_list > ul > li > div.info > h2 > a")   #書名
#以上抓取的都是我們需要的html語言標(biāo)簽信息,我們還需要將他們一一分離出來
for detil,scor,person,title in zip(detils,scors,persons,titles): 
                              #用一個(gè)zip()函數(shù)實(shí)現(xiàn)一次遍歷
#因?yàn)橐恍?biāo)簽中有譯者信息,一些標(biāo)簽中沒有,為避免錯(cuò)誤,所以我們要用一個(gè)try來把他們分開執(zhí)行   
      try:       
           author=detil.get_text().split("/",4)[0].split()[0]     #這是含有譯者信息的提取辦法,根據(jù)“/”  把標(biāo)簽分為五部分,然后依次提取出來
           yizhe= detil.get_text().split("/", 4)[1]            
           publish=detil.get_text().split("/", 4)[2]           
           time=detil.get_text().split("/", 4)[3].split()[0].split("-")[0]   #時(shí)間我們只提取了出版年份  
           price=ceshi_priceone(detil)        #因?yàn)閮r(jià)格的單位不統(tǒng)一,我們用一個(gè)函數(shù)把他們換算為“元”
           scoe=scor.get_text() if True else ""    #有些書目是沒有評(píng)分的,為避免錯(cuò)誤,我們把沒有評(píng)分的信息設(shè)置為空    
           person=ceshi_person(person)      #有些書目的評(píng)價(jià)人數(shù)顯示少于十人,爬取過程中會(huì)出現(xiàn)錯(cuò)誤,用一個(gè)函數(shù)來處理
           title=title.get_text().split()[0]   
#當(dāng)沒有譯者信息時(shí),會(huì)顯示IndexError,我們分開處理
      except IndexError:      
            try:               
                 author=detil.get_text().split("/", 3)[0].split()[0]                
                 yizhe=""         #將detil信息劃分為4部分提取,譯者信息直接設(shè)置為空,其他與上面一樣      
                 publish=detil.get_text().split("/", 3)[1]                
                 time=detil.get_text().split("/", 3)[2].split()[0].split("-")[0]                
                 price=ceshi_pricetwo(detil)               
                 scoe=scor.get_text() if True else ""                
                 person=ceshi_person(person)                
                 title=title.get_text().split()[0]       
            except (IndexError,TypeError):          
                  continue   
#出現(xiàn)其他錯(cuò)誤信息,忽略,繼續(xù)執(zhí)行(有些書目信息下會(huì)沒有出版社或者出版年份,但是數(shù)量很少,不影響我們大規(guī)模爬取,所以直接忽略)
 except TypeError:      
       continue

#提取評(píng)價(jià)人數(shù)的函數(shù),如果評(píng)價(jià)人數(shù)少于十人,按十人處理
def ceshi_person(person):  
     try:       
          person = int(person.get_text().split()[0][1:len(person.get_text().split()[0]) - 4])   
     except ValueError:       
           person = int(10)   
           return person

#分情況提取價(jià)格的函數(shù),用正則表達(dá)式找到含有特殊字符的信息,并換算為“元”
def ceshi_priceone(price):   
        price = detil.get_text().split("/", 4)[4].split()    
        if re.match("USD", price[0]):      
                 price = float(price[1]) * 6   
        elif re.match("CNY", price[0]):       
                 price = price[1]  
        elif re.match("\A$", price[0]):       
                 price = float(price[1:len(price)]) * 6   
        else:       
                 price = price[0]    
       return price
def ceshi_pricetwo(price):    
       price = detil.get_text().split("/", 3)[3].split()   
       if re.match("USD", price[0]):       
               price = float(price[1]) * 6   
       elif re.match("CNY", price[0]):       
               price = price[1]   
       elif re.match("\A$", price[0]):        
               price = float(price[1:len(price)]) * 6    
       else:       
               price = price[0]   
       return price

實(shí)驗(yàn)成功后,我們就可以爬取數(shù)據(jù)并導(dǎo)入到數(shù)據(jù)庫中了,以下為全部源碼,特殊情況會(huì)用注釋一一說明。

import requests
from bs4 import BeautifulSoup
import time
import re
import pymysql
from channel import channel   #這是我們第一個(gè)程序爬取的鏈接信息
import random

def ceshi_person(person):  
     try:       
          person = int(person.get_text().split()[0][1:len(person.get_text().split()[0]) - 4])   
     except ValueError:       
           person = int(10)   
     return person

def ceshi_priceone(price):   
        price = detil.get_text().split("/", 4)[4].split()    
        if re.match("USD", price[0]):      
                 price = float(price[1]) * 6   
        elif re.match("CNY", price[0]):       
                 price = price[1]  
        elif re.match("\A$", price[0]):       
                 price = float(price[1:len(price)]) * 6   
        else:       
                 price = price[0]    
        return price

def ceshi_pricetwo(price):    
       price = detil.get_text().split("/", 3)[3].split()   
       if re.match("USD", price[0]):       
               price = float(price[1]) * 6   
       elif re.match("CNY", price[0]):       
               price = price[1]   
       elif re.match("\A$", price[0]):        
               price = float(price[1:len(price)]) * 6    
       else:       
               price = price[0]   
       return price


#這是上面的那個(gè)測(cè)試函數(shù),我們把它放在主函數(shù)中
def mains(url):
      wb_data = requests.get(url)
      soup = BeautifulSoup(wb_data.text.encode("utf-8"), "lxml")
      tag=url.split("?")[0].split("/")[-1]    
      detils=soup.select("#subject_list > ul > li > div.info > div.pub")  
      scors=soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.rating_nums")   
      persons=soup.select("#subject_list > ul > li > div.info > div.star.clearfix > span.pl")    
      titles=soup.select("#subject_list > ul > li > div.info > h2 > a")   
      for detil,scor,person,title in zip(detils,scors,persons,titles):
            l = []  #建一個(gè)列表,用于存放數(shù)據(jù)
            try:       
                 author=detil.get_text().split("/",4)[0].split()[0] 
                 yizhe= detil.get_text().split("/", 4)[1]            
                 publish=detil.get_text().split("/", 4)[2]           
                 time=detil.get_text().split("/", 4)[3].split()[0].split("-")[0]   
                 price=ceshi_priceone(detil)  
                 scoe=scor.get_text() if True else ""     
                 person=ceshi_person(person)   
                 title=title.get_text().split()[0]   
            except IndexError:      
                  try:               
                       author=detil.get_text().split("/", 3)[0].split()[0]                
                       yizhe=""          
                       publish=detil.get_text().split("/", 3)[1]                
                       time=detil.get_text().split("/", 3)[2].split()[0].split("-")[0]                
                       price=ceshi_pricetwo(detil)               
                       scoe=scor.get_text() if True else ""                
                       person=ceshi_person(person)                
                       title=title.get_text().split()[0]       
                  except (IndexError,TypeError):          
                        continue   

       except TypeError:      
             continue
       l.append([title,scoe,author,price,time,publish,person,yizhe,tag])
                    #將爬取的數(shù)據(jù)依次填入列表中
 

       sql="INSERT INTO allbooks values(%s,%s,%s,%s,%s,%s,%s,%s,%s)"  #這是一條sql插入語句
       cur.executemany(sql,l)   #執(zhí)行sql語句,并用executemary()函數(shù)批量插入數(shù)據(jù)庫中
       conn.commit()

#主函數(shù)到此結(jié)束


# 將Python連接到MySQL中的python數(shù)據(jù)庫中
conn = pymysql.connect( user="root",password="123123",database="python",charset='utf8')
cur = conn.cursor()

cur.execute('DROP TABLE IF EXISTS allbooks')   #如果數(shù)據(jù)庫中有allbooks的數(shù)據(jù)庫則刪除
sql = """CREATE TABLE allbooks(      
        title CHAR(255) NOT NULL,      
        scor CHAR(255),      
        author CHAR(255),     
        price CHAR(255),     
        time CHAR(255),    
        publish CHAR(255),     
        person CHAR(255),     
        yizhe CHAR(255),     
        tag CHAR(255)       
 )"""
cur.execute(sql)  #執(zhí)行sql語句,新建一個(gè)allbooks的數(shù)據(jù)庫


start = time.clock()   #設(shè)置一個(gè)時(shí)鐘,這樣我們就能知道我們爬取了多長(zhǎng)時(shí)間了
for urls in channel.split():    
      urlss=[urls+"?start={}&type=T".format(str(i)) for i in range(0,980,20)]   #從channel中提取url信息,并組裝成每一頁的鏈接
      for url in urlss:       
             mains(url)       #執(zhí)行主函數(shù),開始爬取
             print(url)        #輸出要爬取的鏈接,這樣我們就能知道爬到哪了,發(fā)生錯(cuò)誤也好處理
             time.sleep(int(format(random.randint(0,9))))   #設(shè)置一個(gè)隨機(jī)數(shù)時(shí)間,每爬一個(gè)網(wǎng)頁可以隨機(jī)的停一段時(shí)間,防止IP被封
end = time.clock()
print('Time Usage:', end - start)    #爬取結(jié)束,輸出爬取時(shí)間
count = cur.execute('select * from allbooks')
print('has %s record' % count)       #輸出爬取的總數(shù)目條數(shù)

# 釋放數(shù)據(jù)連接
if cur:   
     cur.close()
if conn:   
     conn.close()

這樣,一個(gè)程序就算完成了,豆瓣的書目信息就一條條地寫進(jìn)了我們的數(shù)據(jù)庫中,當(dāng)然,在爬取的過程中,也遇到了很多問題,比如標(biāo)題返回的信息拆分后中會(huì)有空格,寫入數(shù)據(jù)庫中會(huì)出現(xiàn)錯(cuò)誤,所以只截取了標(biāo)題的第一部分,因而導(dǎo)致數(shù)據(jù)庫中的一些書名不完整,過往的大神如果有什么辦法,還請(qǐng)指教一二。
等待爬取的過程是漫長(zhǎng)而又欣喜的,看著電腦上一條條信息被刷出來,成就感就不知不覺涌上心頭;然而如果你吃飯時(shí)它在爬,你上廁所時(shí)它在爬,你都已經(jīng)爬了個(gè)山回來了它還在爬時(shí),便會(huì)有點(diǎn)崩潰了,擔(dān)心電腦隨時(shí)都會(huì)壞掉(還是窮學(xué)生換不起啊啊啊啊~)
所以,還是要好好學(xué)學(xué)設(shè)置斷點(diǎn),多線程,以及正則,路漫漫其修遠(yuǎn)兮,吾將上下而求索共勉

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容