完整代碼可以關(guān)注公眾號(hào):Romi的雜貨鋪
首先打開京東的任意幾個(gè)商品頁(yè)面,并觀察URL添祸,可以發(fā)現(xiàn)都是https://item.jd.com/+數(shù)字+.htm的格式趾断,而且數(shù)字也隨著商品的改變而改變媚送,基本上可以確定這串?dāng)?shù)字是商品ID
之后我們找到網(wǎng)頁(yè)的源碼并隨便復(fù)制一句評(píng)論,在網(wǎng)頁(yè)源碼中查找羽戒,發(fā)現(xiàn)并沒(méi)有找到評(píng)論內(nèi)容缤沦,說(shuō)明jd的評(píng)論頁(yè)面并非靜態(tài)網(wǎng)頁(yè)
AJAX:
AJAX的全稱是Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)。
ajax不是新的編程語(yǔ)言易稠,而是一種使用現(xiàn)有標(biāo)準(zhǔn)的新方法缸废。ajax是與服務(wù)器交換數(shù)據(jù)并更新部分網(wǎng)頁(yè)的藝術(shù),在不重新加載整個(gè)頁(yè)面的情況下驶社。
ajax是一種在無(wú)需重新加載整個(gè)網(wǎng)頁(yè)的情況下企量,能夠更新部分網(wǎng)頁(yè)的技術(shù)。
ajax是一種用于創(chuàng)建快速動(dòng)態(tài)網(wǎng)頁(yè)的技術(shù)亡电。通過(guò)在后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換届巩。ajax可以使網(wǎng)頁(yè)實(shí)現(xiàn)異步更新。這意味著可以在不重新加載整個(gè)網(wǎng)頁(yè)的情況下份乒,對(duì)網(wǎng)頁(yè)的某部分進(jìn)行更新恕汇。而傳統(tǒng)的網(wǎng)頁(yè)(不使用ajax)如果需要更新內(nèi)容,必須重載整個(gè)網(wǎng)頁(yè)面或辖。
既然確定是AJAX的方式加載瘾英,我們可以直接打開chrome的調(diào)試工具,在network中的XHR和JS中尋找保存有評(píng)論的文件颂暇。注意這里必須先下拉到評(píng)論頁(yè)面使數(shù)據(jù)文件加載下來(lái)缺谴,否則會(huì)找不到加載的數(shù)據(jù)文件
我們可以通過(guò)兩種方式來(lái)查找包含評(píng)論的文件:
1.可以在js和XHR中尋找comment關(guān)鍵字,查看是否有文件符合要求耳鸯,并對(duì)符合要求的結(jié)果篩選
2.評(píng)論在頁(yè)面的最下方瓣赂,根據(jù)文件的加載順序可以大致了解到會(huì)在后面榆骚,從后面開始找即可
最終確定js文件,如下圖所示
這樣我們就可以確定評(píng)論的請(qǐng)求地址并開始抓取
import requestsimport jsonurl='https://item.jd.com/52297931949.html'jsonurl='https://club.jd.com/comment/productPageComments.action?productId=52297931949&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1'html=requests.get(jsonurl).text#print(html)josntext=json.loads(html)comments= josntext['comments']for comment in comments: content = comment['content'] print(content)
這里需要注意一下原始的jsonurl得到的文件并不是標(biāo)準(zhǔn)的json文件格式煌集,我們可以將得到的文本內(nèi)容復(fù)制到https://www.json.cn發(fā)現(xiàn)這并不是一個(gè)標(biāo)準(zhǔn)的josn文件妓肢,所以直接loads()會(huì)直接報(bào)錯(cuò):json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0),只要返
回的對(duì)象不是josn對(duì)象就會(huì)出現(xiàn)此錯(cuò)誤
解決的方法有兩個(gè)苫纤,一是將URL中的?callback=fetchJSON_comment98去除碉钠,另外一種方法是將返回的文本對(duì)象中的fetchJSON_comment98替換為空
得到所需要的json文件后就可以將數(shù)據(jù)存到sqllite中了
sqllite是python內(nèi)置的關(guān)系型數(shù)據(jù)庫(kù),具有以下優(yōu)點(diǎn):
不需要一個(gè)單獨(dú)的服務(wù)器進(jìn)程或操作的系統(tǒng)(無(wú)服務(wù)器的)卷拘。
SQLite不需要配置喊废,這意味著不需要安裝或管理。
一個(gè)完整的SQLite數(shù)據(jù)庫(kù)是存儲(chǔ)在一個(gè)單一的跨平臺(tái)的磁盤文件栗弟。
SQLite是非常小的污筷,是輕量級(jí)的,完全配置時(shí)小于 400KiB乍赫,省略可選功能配置時(shí)小于250KiB瓣蛀。
SQLite是自給自足的,這意味著不需要任何外部的依賴雷厂。
SQLite事務(wù)是完全兼容 ACID 的惋增,允許從多個(gè)進(jìn)程或線程安全訪問(wèn)。
SQLite支持 SQL92(SQL2)標(biāo)準(zhǔn)的大多數(shù)查詢語(yǔ)言的功能改鲫。
SQLite使用 ANSI-C 編寫的诈皿,并提供了簡(jiǎn)單和易于使用的 API。
SQLite 在 UNIX(Linux, Mac OS-X, Android,iOS)和 Windows(Win32, WinCE,WinRT)中運(yùn)行像棘。
python操作SQLite流程與連接其他的數(shù)據(jù)庫(kù)相同稽亏,大概分為以下五步
通過(guò)sqlite3.open()創(chuàng)建與數(shù)據(jù)庫(kù)文件的連接對(duì)象connection;
通過(guò)connection.cursor()創(chuàng)建光標(biāo)對(duì)象cursor缕题;
通過(guò)cursor.execute()執(zhí)行SQL語(yǔ)句措左;
通過(guò)connection.commit()提交當(dāng)前的事務(wù),或者通過(guò)cursor.fetchall()獲得查詢結(jié)果避除;
通過(guò)connection.close()關(guān)閉與數(shù)據(jù)庫(kù)文件的連接
這一部分代碼如下所示
conn=sqlite3.connect("comments.db")#建立連接,數(shù)據(jù)庫(kù)存在時(shí)胸嘁,直接連接瓶摆;不存在時(shí),創(chuàng)建相應(yīng)數(shù)據(jù)庫(kù)#新建一張表conn.execute('''CREATE TABLE Comments_jd (ID text PRIMARY KEY NOT NULL, comment text );''')#注意sql語(yǔ)句中使用了格式化輸出的占位符%s和%d來(lái)表示將要插入的變量性宏,其中%s需要加引號(hào)''for comment in comments: sql = "insert into Comments_jd(ID,comment) values('%s','%s')" % (comment['id'],comment['content']) conn.execute(sql)conn.commit()# 關(guān)閉數(shù)據(jù)庫(kù)連接conn.close()
之后檢查以下數(shù)據(jù)是否有問(wèn)題:
conn=sqlite3.connect("comments.db")cursor = conn.execute("select * from Comments_jd")for row in cursor: print('ID = ', row[0], ' Comment = ', row[1])conn.close()
得到的結(jié)果如下圖所示
這樣整個(gè)流程就搞定了