豆瓣讀書“編程”類目下顯示有16.1萬(wàn)本書祝辣,但是一頁(yè)一頁(yè)去翻,只能翻到第50頁(yè)瓦灶。再往后就沒有數(shù)據(jù)了....所以這里只爬了前50頁(yè)的數(shù)據(jù)奶陈。
下面的代碼在python3中執(zhí)行有效。
目的:獲取前50頁(yè)每本書的名字
蔚舀,ID
饵沧,封面圖
,內(nèi)容簡(jiǎn)介
赌躺,并保存到數(shù)據(jù)庫(kù)中狼牺。
1. 思路
先打開圖書頁(yè)面,可以看到每頁(yè)展示20本書礼患。
然后再看一下頁(yè)面的URL是钥,https://book.douban.com/tag/編程?start=0&type=T
。
關(guān)注一下里面的兩個(gè)參數(shù)start
和type
缅叠。
當(dāng)頁(yè)面是第一頁(yè)的時(shí)候悄泥,start=0
,在第二頁(yè)的時(shí)候肤粱,start=20
弹囚。所以這個(gè)參數(shù)的規(guī)律就是20*第幾頁(yè)。
參數(shù)type
领曼,表示的應(yīng)該就是當(dāng)前的圖書分類鸥鹉。
知道了URL的規(guī)律之后,一種比較簡(jiǎn)單的思路就是:先進(jìn)入第一頁(yè)悯森,獲取當(dāng)前頁(yè)面20本書的鏈接宋舷,之后循環(huán)獲取每本書的詳細(xì)信息绪撵。然后再跳轉(zhuǎn)到第二頁(yè)瓢姻,繼續(xù)上面的動(dòng)作。直到結(jié)束(第50頁(yè))音诈。
2. 實(shí)現(xiàn)過(guò)程
1) 項(xiàng)目依賴
pymysql: 用來(lái)操作數(shù)據(jù)庫(kù)
requests:發(fā)送請(qǐng)求幻碱,并獲取頁(yè)面源代碼
pyquery:操作dom绎狭,獲取dom的值。類似jquery
2)代碼
額褥傍,打字好累儡嘶,直接粘貼代碼吧。恍风。蹦狂。。朋贬。
# 抓取豆瓣讀書某個(gè)分類下的全部書籍簡(jiǎn)介
import pymysql
import requests
import time
from pyquery import PyQuery as pq
# 分類的第一頁(yè)凯楔,程序開始的起點(diǎn)
page = 1
type = 'T' # 用來(lái)標(biāo)識(shí)書籍類型
urlArr = [0 for i in range(20)] # 存放當(dāng)前頁(yè)面的20條書本鏈接
bookIDSql = []
# 鏈接數(shù)據(jù)庫(kù)
# 這里的urer/password/bd,需要對(duì)應(yīng)替換成你自己的锦募,prot默認(rèn)是3306就可以了
db = pymysql.connect(host="localhost", user="root", password="123456", port=3306, db="mydatabase")
cursor = db.cursor()
cursor.execute("SELECT bookID FROM doubanBooksInfo")
data = cursor.fetchall()
# 獲取數(shù)據(jù)庫(kù)中現(xiàn)有的bookID
for item in data:
bookIDSql.append(item[0])
print("已經(jīng)存在的bookID:", bookIDSql)
# 獲取當(dāng)前頁(yè)面的book鏈接摆屯,并放進(jìn)數(shù)組urlArr
def getPageUrls (page, type):
offset = 20 * (page - 1)
url = 'https://book.douban.com/tag/編程?start=' + str(offset) + '&type=' + str(type)
listPageReq = requests.get(url)
resTxt = pq(listPageReq.text)
pageUrlList = resTxt('.subject-item')
try:
if (pageUrlList):
index = 0
for item in pageUrlList:
itempq = pq(item)
thisUrl = itempq('.pic').find('a').attr('href')
urlArr[index] = thisUrl
index = index + 1
except:
print('報(bào)錯(cuò)了...')
# 從urlArr中依次取出鏈接,訪問頁(yè)面糠亩,獲取該頁(yè)面書籍的信息
def getBookInfo (url):
# 如果當(dāng)前id不存在于id列表虐骑,則進(jìn)行獲取書籍信息的操作
if (checkBookID(getBookIDFromUrl(url), bookIDSql)):
bookPageReq = requests.get(url)
resTxt = pq(bookPageReq.text)
contentWrapper = resTxt('#link-report .intro').find('p')
# 書的ID
bookID = url.split('/')[-2]
# 書名
bookName = resTxt('#mainpic a').attr('title')
# 封面圖
bookImg = resTxt('#mainpic a').attr('href')
# 書的簡(jiǎn)介
bookContent = ''
# 把多段文字拼合在一起
for tag in contentWrapper:
if (tag.text):
bookContent = bookContent + tag.text
# 插入到數(shù)據(jù)庫(kù)中
inertDataToSql(bookID, bookName, bookImg, bookContent)
# 把非重復(fù)的數(shù)據(jù)插入到數(shù)據(jù)庫(kù)中
def inertDataToSql (bookID, bookName, bookImg, bookContent):
sql = "INSERT INTO doubanBooksInfo(bookID, name, img, content) values (%s, %s, %s, %s)"
try:
cursor.execute(sql, (bookID, bookName, bookImg, bookContent))
db.commit()
except:
db.rollback()
# 檢驗(yàn)當(dāng)前的id是否存在id列表中
def checkBookID (currentID, bookIDList):
if (currentID not in bookIDList):
bookIDList.append(currentID)
print('該ID尚未存在,可以進(jìn)行抓取')
print('已經(jīng)抓取數(shù)量:', bookIDList.__len__())
return True
# 從url中獲取當(dāng)前的bookID
def getBookIDFromUrl (url):
currentID = url.split('/')[-2]
return currentID
# 讓程序不斷的執(zhí)行赎线,直到第50頁(yè)
endPage = 51
while (page < endPage):
print('目前在第:', page, '頁(yè)')
getPageUrls(page, 'T')
for url in urlArr:
getBookInfo(url)
time.sleep(2)
page = page + 1
數(shù)據(jù)庫(kù)截圖:
——————
程序很爛廷没,希望后面會(huì)有時(shí)間優(yōu)化。垂寥。腕柜。