基礎知識
1 js:JavaScript縮寫
json:JavaScript的一種數據格式
2 瀏覽器的原理:把 html+css+js 下載到本地然后再進行渲染。即看到網頁這個過程,實際上是瀏覽器把代碼下載下來,然后瀏覽器來解釋這個代碼,變成界面的過程。
3 查看網頁源代碼:就是別人服務器發送到瀏覽器的原封不動的代碼。這個代碼沒有被瀏覽器執行js。
(F12)檢查元素:檢查元素時,在源代碼中找不到的代碼,是在瀏覽器執行js動態生成的。通過檢查元素看到的就是最終的html代碼。即:源代碼 + 網頁js渲染
數據的存放
網頁的數據有兩種存放方法:①存在“網頁源代碼”里。
②存在后端(數據庫)里。
注意:存在“網頁源代碼”里的數據也可能存在數據庫里。
獲取網頁的代碼
① 使用requests.get()
使用該方法請求網頁,得到的是網頁源代碼。因為requests請求庫不能執行js,所以js無法渲染。如果網頁的數據存在“網頁源代碼”里,那么使用該方法能獲取到這些數據;如果網頁的數據存在后端(數據庫)里,那么使用該方法就不能獲取這些數據了。因為后端的數據需要瀏覽器執行js才能動態生成。
② 使用selenium自動化技術
爬蟲中使用selenium主要是為了解決requests無法執行javaScript代碼的問題。selenium本質上是通過驅動瀏覽器,完成模擬瀏覽器的操作,比如跳轉、輸入、點擊、下拉等...進而拿到網頁渲染之后的結果。如果你的網站需要發送ajax請求,異步獲取數據渲染到頁面上,就需要使用js發送請求。selenium可以模擬瀏覽器執行js。使用selenium模擬瀏覽器,得到的是最終的html代碼,即:源代碼 + 網頁js渲染。但是它也有缺點,因為使用selenium本質上是驅動瀏覽器對目標站點發送請求,那瀏覽器在訪問目標站點的時候,需要把靜態資源都加載完畢。html、css、js這些文件都要等待它們加載完成,導致速度很慢。所以我們一般用它來做登錄驗證。不管網頁的數據存在“網頁源代碼”里,還是存在數據庫里,使用該方法能獲取到所有的數據。
爬蟲的思路:
查看網頁源代碼里是否有我們需要的數據。
如果有,直接使用requests.get()方法獲取。當使用該方法獲取數據較困難時,也可以查看http協議的接口是否有數據,有的話就可以使用(1)或者(2)的方法。
如果沒有,有兩種方法:
(1) 調用接口:查看數據所在的http協議接口,然后獲取該接口的url,再使用第requests.get種方法進行請求。
(2) 使用selenium自動化技術。遇到加密的接口時,使用該方法就能繞過加密。
智能等待
使用selenium模擬瀏覽器有時候會報一個錯誤:使用xpath找不到需要定位的數據元素。但該數據元素的路徑是正確的,出現這種問題的原因是沒有設置等待時間。因為瀏覽器執行js是需要時間的,只有等到網頁js渲染完成后,數據才能加載在最終的html代碼里,如果沒有等到數據加載到最終的html代碼里就獲取頁面代碼,自然就找不到數據元素了。因此我們需要設置等待時間,讓網頁js渲染完成后再對數據元素進行定位。
selenium有三種等待的方式
①time.sleep(等待時間)
這種方法是選擇一個固定的時間進行等待,單位是秒。使用時需要引入time模塊。 import time
②implicitly_wait(等待時間)
這種方法是判斷在設定的時間內頁面是否加載完成,如果加載完成那么就進行下一步,如果沒加載完成就會報超時加載的錯誤。使用時需要引入time模塊。 import time
③推薦使用:WebDriverWait(driver,時間)
from selenium.webdriver.support.ui import WebDriverWait WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath('指定元素路徑')) # driver是操作 webdriver.Chrome()的句柄。 # 在10秒內每隔500毫秒掃描1次頁面變化,當出現指定的元素后就結束等待,進行下一步。 # until代表一直等待,直到某元素可見為止。
selenium操作對象的text方法
1 使用 driver.find_element_by_xpath("xpath路徑") 定位到單個元素后,直接使用text方法,即可獲取元素的文本。即 driver.find_element_by_xpath("xpath路徑").text
2 使用 driver.find_elements_by_xpath("xpath路徑") 定位到一組元素后,先使用for循環把每個元素遍歷出來,遍歷出來后再對單個元素使用text方法獲取單個元素的文本。
如何查找一組元素的xpath路徑呢?任意選擇幾個同組元素的xpath路徑來進行對比,找到這幾個路徑中不一樣的地方,然后提取公共部分就是這組元素的xpath路徑。通過這組元素的xpath路徑就能夠定位到這組的所有元素。
1 yizuyuansu = driver.find_elements_by_xpath("一組元素的xpath路徑") 2 for yigeyuansu in yizuyuansu: 3 print(yigeyuansu.text)
一、抓取深圳證券交易所的信息
目標:打開 http://www.szse.cn/market/stock/indicator/index.html ,出現如下頁面。我們的目標是要獲取深圳市場、深市主板、中小企業板、創業板下的數據。
分析:查找網頁源代碼,發現並沒有我們需要的數據。而在接口中發現了我們需要的數據。所以該網站把我們需要的數據存在接口里。
獲取數據的方法:①通過接口 ②使用xpath獲取我們需要的數據所在的元素后,使用selinum的text方法來獲取這些元素的文本。
1 def get_informations_by_interface(interface_shenzhenshichang_url,interface_shenshizhuban_url,interface_zhongxiaoqiyeban_url,interface_chuangyeban_url): 2 import requests 3 4 #深圳市場 5 shenzhenshichang = requests.get(interface_shenzhenshichang_url) 6 # requests中內置一個JSON解碼器,幫助處理JSON數據。通過json()方法可以把返回對象為json格式的字符串轉化為字典。 7 shenzhenshichang = shenzhenshichang.json() 8 shenzhenshichang = shenzhenshichang[0]['data'] 9 for data in shenzhenshichang: 10 print('===================') 11 print('指標名稱:' + data['zbmc']) 12 print('本日數值:' + data['brsz']) 13 print('比上日增減:' + data['bsrzj']) 14 print('幅度%:' + data['fd']) 15 print('本年最高:' + data['bnzg']) 16 print('最高值日期:' + data['zgzrq']) 17 18 #深市主板 19 shenshizhuban = requests.get(interface_shenshizhuban_url) 20 shenshizhuban = shenshizhuban.json() 21 shenshizhuban = shenshizhuban[1]['data'] 22 for data in shenshizhuban: 23 print('===========================') 24 print('指標名稱:' + data['indicator']) 25 print('本日數值:' + data['today']) 26 print('比上日增減:' + data['increase']) 27 print('本年最高:' + data['highofyear']) 28 print('最高值日期:' + data['dateofhigh']) 29 30 #中小企業板 31 zhongxiaoqiyeban = requests.get(interface_zhongxiaoqiyeban_url) 32 zhongxiaoqiyeban = zhongxiaoqiyeban.json() 33 zhongxiaoqiyeban = zhongxiaoqiyeban[2]['data'] 34 for data in zhongxiaoqiyeban: 35 print('===========================') 36 print('指標名稱:' + data['indicator']) 37 print('本日數值:' + data['today']) 38 print('比上日增減:' + data['increase']) 39 print('本年最高:' + data['highofyear']) 40 print('最高值日期:' + data['dateofhigh']) 41 42 #創業板 43 chuangyeban = requests.get(interface_chuangyeban_url) 44 chuangyeban = chuangyeban.json() 45 chuangyeban = chuangyeban[3]['data'] 46 for data in chuangyeban: 47 print('===========================') 48 print('指標名稱:' + data['indicator']) 49 print('本日數值:' + data['today']) 50 print('比上日增減:' + data['increase']) 51 print('本年最高:' + data['highofyear']) 52 print('最高值日期:' + data['dateofhigh']) 53 54 def get_informations_by_selenium(url): 55 from selenium import webdriver 56 import requests 57 from selenium.webdriver.support.ui import WebDriverWait 58 import time 59 60 driver = webdriver.Chrome() 61 driver.maximize_window() 62 driver.get(url) 63 64 WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath('//*[@id="1803_nav1"]')) 65 shenzhenshichang_text = driver.find_element_by_xpath('//*[@id="1803_nav1"]').text 66 print(shenzhenshichang_text) 67 print('=================================================================================') 68 69 # 此處我使用time.sleep(1)等待頁面加載,運行時,一切正常。后做優化,想使用WebDriverWait 代替time.sleep,但是會時不時出現click失效的情況。 70 # 出現問題原因:html文檔加載出來了,但是對應的圖標還沒加載出來,所以當時點擊無效 71 # 解決方法:在WebDriverWait 語句后面,適當加一點的休息時間,即time.sleep 72 driver.find_element_by_xpath('//*[@id="1803_tabs"]/div[1]/div[1]/ul/li[2]/a').click() 73 WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath('//*[@id="1803_nav2"]')) 74 time.sleep(1) 75 shenshizhuban_text = driver.find_element_by_xpath('//*[@id="1803_nav2"]').text 76 print(shenshizhuban_text) 77 print('==================================================================================') 78 79 driver.find_element_by_xpath('//*[@id="1803_tabs"]/div[1]/div[1]/ul/li[3]/a').click() 80 WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath('//*[@id="1803_nav3"]')) 81 time.sleep(1) 82 zhongxiaoqiyeban_text = driver.find_element_by_xpath('//*[@id="1803_nav3"]').text 83 print(zhongxiaoqiyeban_text) 84 print('===================================================================================') 85 86 driver.find_element_by_xpath('//*[@id="1803_tabs"]/div[1]/div[1]/ul/li[4]/a').click() 87 WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath('//*[@id="1803_nav4"]')) 88 time.sleep(1) 89 chuangyeban_text = driver.find_element_by_xpath('//*[@id="1803_nav4"]').text 90 print(chuangyeban_text) 91 92 93 94 if __name__ == '__main__': 95 interface_shenzhenshichang_url = 'http://www.szse.cn/api/report/ShowReport/data?SHOWTYPE=JSON&CATALOGID=1803&loading=first&random=0.049964627342305334' 96 interface_shenshizhuban_url = 'http://www.szse.cn/api/report/ShowReport/data?SHOWTYPE=JSON&CATALOGID=1803&TABKEY=tab2&txtQueryDate=2020-07-06&random=0.8286262855952344' 97 interface_zhongxiaoqiyeban_url = 'http://www.szse.cn/api/report/ShowReport/data?SHOWTYPE=JSON&CATALOGID=1803&TABKEY=tab3&txtQueryDate=2020-07-06&random=0.5038392303025343' 98 interface_chuangyeban_url = 'http://www.szse.cn/api/report/ShowReport/data?SHOWTYPE=JSON&CATALOGID=1803&TABKEY=tab4&txtQueryDate=2020-07-06&random=0.9404614845941501' 99 url = 'http://www.szse.cn/market/stock/indicator/index.html' 100 101 get_informations_by_interface(interface_shenzhenshichang_url,interface_shenshizhuban_url,interface_zhongxiaoqiyeban_url,interface_chuangyeban_url) 102 get_informations_by_selenium(url)
二、抓取QQ音樂歌詞和歌曲信息
目標:打開 https://y.qq.com/n/yqq/song/004dcSDN0czi28.html ,出現如下頁面。我們的目標是要獲取這首歌的歌詞和歌曲信息。
分析:查找網頁源代碼,發現並沒有歌詞。而在一個接口中發現了歌詞。因為歌曲信息在源代碼中很難匹配出來,接口中又存在歌曲信息,所以選擇使用接口獲取歌曲信息。
獲取歌詞的方法:①通過接口 ②使用xpath找到歌詞元素后,使用selenium的text方法來獲取歌詞元素的文本。
注意:使用selenium時,打開頁面后,我們需要先點擊圖片上的“展開”,把歌詞在頁面中顯示完整,此時使用text方法來獲取歌詞元素的文本才是完整的歌詞。如果不點擊“展開”,那么使用text方法來獲取歌詞元素的文本只有頁面中顯示的那部分不完整的歌詞。
1 def get_qqmusic_lyrics_by_selenium(url): 2 from selenium import webdriver 3 import requests 4 from selenium.webdriver.support.ui import WebDriverWait 5 import time 6 7 driver = webdriver.Chrome() 8 driver.maximize_window() 9 driver.get(url) 10 11 # 此處我使用time.sleep(1)等待頁面加載,運行時,一切正常。后做優化,想使用WebDriverWait 代替time.sleep,但是會時不時出現click失效的情況。 12 # 出現問題原因:html文檔加載出來了,但是對應的圖標還沒加載出來,所以當時點擊無效 13 # 解決方法:在WebDriverWait 語句后面,適當加一點的休息時間,即time.sleep 14 WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath('//a[@class="c_tx_highlight js_open_lyric"]')) 15 time.sleep(2) 16 17 # 點擊“展開”歌詞 18 driver.find_element_by_xpath('/html/body/div[2]/div[2]/div[1]/div[1]/div[2]/a').click() 19 WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath('//*[@id="lrc_content"]')) 20 21 # 使用xpath定位到歌詞后,獲取歌詞文本 22 lyric_text = driver.find_element_by_xpath('//*[@id="lrc_content"]').text 23 print(lyric_text) 24 25 def get_qqmusic_informations_by_interface(informations_interface_url): 26 import requests 27 response = requests.get(information_interface_url) 28 29 # requests中內置一個JSON解碼器,幫助處理JSON數據。通過json()方法可以把返回對象為json格式的字符串轉化為字典。 30 response = response.json() 31 32 print(response['songinfo']['data']['info']['genre']['title'] + ':' + response['songinfo']['data']['info']['genre']['content'][0]['value']) 33 print(response['songinfo']['data']['info']['company']['title'] + ':' + response['songinfo']['data']['info']['company']['content'][0]['value']) 34 print(response['songinfo']['data']['info']['lan']['title'] + ':' + response['songinfo']['data']['info']['lan']['content'][0]['value']) 35 print(response['songinfo']['data']['info']['pub_time']['title'] + ':' + response['songinfo']['data']['info']['pub_time']['content'][0]['value']) 36 37 def get_qqmusic_lyrics_by_interface(lyrics_interface_url): 38 import requests 39 import html 40 # 我第一次沒加請求頭就發送請求,結果請求不成功,加了這個請求i頭后請求才成功。因此有的接口的請求需要加請求頭。 41 headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36', 42 'referer': 'https://y.qq.com/n/yqq/song/004dcSDN0czi28.html'} 43 response = requests.get(lyrics_interface_url,headers=headers) 44 45 # requests中內置一個JSON解碼器,幫助處理JSON數據。通過json()方法可以把返回對象為json格式的字符串轉化為字典。 46 response = response.json() 47 48 lyrics = response['lyric'] 49 # html實體反轉義字符。 50 lyrics = html.unescape(lyrics) 51 print(lyrics) 52 53 if __name__ == '__main__': 54 qqmusic_url = '歌曲鏈接' 55 information_interface_url = '歌曲信息的接口鏈接' 56 lyrics_interface_url = '歌詞的接口鏈接' 57 58 get_qqmusic_lyrics_by_selenium(qqmusic_url) 59 print('======================================') 60 get_qqmusic_informations_by_interface(information_interface_url) 61 print('======================================') 62 get_qqmusic_lyrics_by_interface(lyrics_interface_url)
三、抓取京東大地瓜價格和名字
目標:打開 https://search.jd.com/Search?keyword=%E5%A4%A7%E5%9C%B0%E7%93%9C&enc=utf-8&wq=%E5%A4%A7%E5%9C%B0%E7%93%9C&pvid=1ea2204782724a3bbbd3df7ef5d74b93 ,出現如 下頁面,我們的目標是要獲取每頁中的60個商品的價格和名字。
分析: 查找網頁源代碼,發現只存在30個商品元素。而在一個接口中,找到了剩下的30個商品元素。
獲取一頁商品價格的方法:①先從源碼中取出30個商品的價格和名字,再通過接口取出剩下的30個商品的價格和名字。 ②使用xpath找到一頁中的60個價格元素后,使用selenium的text方法來獲取這60個價格元素的文本。
對於前五頁,只需要一個for循環對url進行循環即可解決。
使用第②種方法的注意事項:
1 因為打開鏈接后頁面源碼默認存在30個商品元素,也就是說如果我們不把頁面滾動條拖到底部,那么我們只能獲取到30個商品價格元素。當我們把頁面滾動條拖到最底部后,頁面源碼中就有60個商品價格元素了。可以通過js代碼實現拖動頁面滾動條。
#1 將普通頁面滾動條拖到底部,如果想把滾動條拖到頂部,只需要把10000改為0即可 js="var q=document.documentElement.scrollTop=10000" driver.execute_script(js) #2 將內嵌窗口(例如第一次進入游戲中需要閱讀的游戲須知窗口)的頁面滾動條拖到底部,需要先找到內嵌窗口元素的id js="var q=document.getElementById('id').scrollTop=10000" driver.execute_script(js)
2 因為我們要的是頁面上的60個價格,即一組價格數據。因此使用 driver.find_elements_by_xpath 來查找這組價格元素,而不是 driver.find_element_by_xpath 。
先任選一個價格元素的xpath路徑(比如第一個://*[@id="J_goodsList"]/ul/li[1]/div/div[2]/strong/i ),再任選一個價格元素的xpath路徑(比如第二個://*[@id="J_goodsList"]/ul/li[2]/div/div[2]/strong/i ),通過對比這兩個xpath路徑后發現,它們的不同是路徑中標黃的li[1]和li[2]部分,因此我們把路徑中標黃的li后面的[1]或者[2]去掉后,得到的就是這組價格元素的路徑。即://*[@id="J_goodsList"]/ul/li/div/div[2]/strong/i 。使用xpath定位到這組價格元素后,通過for循環把60個價格元素遍歷出來,然后讀取每個價格元素的文本就是我們需要的價格數據。60個商品的名字同理。
1 #該函數通過selenium獲取京東大地瓜商品第一頁的商品價格,一共有60個商品。 2 def get_informations_by_selenium(): 3 from selenium import webdriver 4 import requests 5 from selenium.webdriver.support.ui import WebDriverWait 6 import time 7 8 driver = webdriver.Chrome() 9 driver.maximize_window() 10 driver.get( 11 'https://search.jd.com/Search?keyword=%E5%A4%A7%E5%9C%B0%E7%93%9C&qrst=1&wq=%E5%A4%A7%E5%9C%B0%E7%93%9C&stock=1&page=1&s=1&click=0') 12 WebDriverWait(driver, 10).until( 13 lambda driver: driver.find_element_by_xpath('//*[@id="J_goodsList"]/ul/li/div/div[2]/strong/i')) 14 15 # 將頁面滾動條拖到底部,可以作為固定寫法。 16 js = "var q=document.documentElement.scrollTop=10000" 17 driver.execute_script(js) 18 time.sleep(3) 19 20 price_elements = driver.find_elements_by_xpath('//*[@id="J_goodsList"]/ul/li/div/div[2]/strong/i') 21 for price_element in price_elements: 22 print(price_element.text) 23 print(len(price_elements)) 24 25 26 #該函數通過網頁源代碼和接口共同獲取京東大地瓜商品前5頁的商品價格和名稱,每頁都有60個商品。 27 '''思路: 28 前30個商品的數據在網頁源代碼,我們可以請求網頁源代碼后使用xpath獲取。把前30個商品的價格和名字存到一個價格列表和一個名字列表里。 29 1 獲取的是30個商品的xpath路徑。 30 做法是:①對比n個商品的xpath價格路徑,得到30個商品的xpath價格路徑; 31 ②對比n個商品的xpath名字路徑,得到30個商品的xpath名字路徑。 32 ③對比30個商品的xpath價格路徑和30個商品的xpath名字路徑,得到30個商品的路徑。 33 34 比如這是第一個商品的xpath價格路徑://*[@id="J_goodsList"]/ul/li[1]/div/div[2]/strong/i 35 這是第二個商品的xpath價格路徑://*[@id="J_goodsList"]/ul/li[2]/div/div[2]/strong/i 36 所以30個商品的xpath價格路徑是://*[@id="J_goodsList"]/ul//li/div/div[2]/strong/i 37 38 比如這是第一個商品的xpath名字路徑://*[@id="J_goodsList"]/ul/li[1]/div/div[3]/a/em 39 這是第二個商品的xpath名字路徑://*[@id="J_goodsList"]/ul/li[2]/div/div[3]/a/em 40 所以30個商品的xpath名字路徑是://*[@id="J_goodsList"]/ul//li/div/div[3]/a/em 41 42 比如這是30個商品的xpath價格路徑://*[@id="J_goodsList"]/ul//li/div/div[2]/strong/i 43 這是30個商品的xpath名字路徑://*[@id="J_goodsList"]/ul//li/div/div[3]/a/em 44 所以30個商品的路徑是://*[@id="J_goodsList"]/ul//li/div 45 46 2 得到30個商品的路徑后,把每個商品遍歷出來。並且同時獲取該商品的價格和名字,使得獲取的一個商品的價格和名字一一對應。 47 3 遍歷取出每一個商品的價格和名字后,添加到價格列表和名字列表。因為列表是有序的,價格和名字同時添加能一一對應上。 48 注:因為獲取到的每一個商品名字,都夾雜着空格換行等。所以需要使用''.join(seq)的方法把獲取到的每一個格式為字符串的名字進行重新拼接。拼接后再添加到名字列表里。 49 ''' 50 51 '''思路: 52 后30個商品的數據在一個get接口里。我們需要獲取這個接口的url,然后發送請求,在返回的代碼中找出后30個商品的數據。 53 1 觀察第一頁的get接口的url:https://search.jd.com/s_new.php?keyword=%E5%A4%A7%E5%9C%B0%E7%93%9C&qrst=1&wq=%E5%A4%A7%E5%9C%B0%E7%93%9C&stock=1&page=2&s=26&scrolling=y&log_id=1594065480723.2392&tpl=1_M&isList=0&show_items=70420536815,7713680,57318822454,30055576938,57318822453,30872758383,69922945312,53766745353,60888146009,48104226309,51773251563,29814344646,50404645676,41600013322,51709357916,67097609456,65925516601,64143955809,65514287148,53132376874,65509103991,59878621907,52079997901,57681653424,69514509700,57719320185,71052393509,69896760089,66685136093,60911474440 54 再觀察第一頁的網頁源代碼的url:https://search.jd.com/Search?keyword=%E5%A4%A7%E5%9C%B0%E7%93%9C&qrst=1&wq=%E5%A4%A7%E5%9C%B0%E7%93%9C&stock=1&page=1&s=1&click=0 55 發現第一頁的網頁源代碼的url中存在“page=1”,get接口的url中存在“page=2”, 56 此時我們再去觀察第二頁,發現網頁源代碼的url中存在”page=3“,get接口的url中存在“page=4”, 57 第三頁的網頁源代碼的url中存在“page=5”,get接口的url中存在“page=6”. 58 此時我們發現一個規律:第n頁的網頁源代碼的page等於2n-1,get接口的url的page等於2n。 59 60 2 觀察每一頁的get接口的url,發現“items=”往后的部分都有30個數字,因此我們知道這30個數字與后30個商品一一對應。 61 我們只需要找到每一頁的后30個商品對應的30個數字,再進行拼接就能得到每一頁的get接口的url。 62 我們發現,后30個商品對應的30個數字都在網頁源代碼里,因此我們可以先獲取網頁源代碼,然后使用正則表達式把后30個商品對應的數字匹配出來。 63 我們發現匹配的結果里每個數字都有3個重復的,即匹配到90個數字。此時我們可以通過集合的去重功能匹配出我們需要的30個數字。 64 得到30個數字后,我們再進行字符串拼接,就能得到get接口的url。注意每一頁get接口的url中page對應的規則是2n。 65 66 3 get接口的url拼接成功后,發送一個get請求,得到的代碼里就包括了剩下的30個商品數據。 67 注意:發送請求時需要攜帶請求頭,不然會觸發京東頁面登陸機制。 68 因為后30個商品的標簽和在源碼里前30個商品的標簽是差不多的,因此我們可以仿照前30個商品的xpath路徑,即//li/div。 69 70 4 獲取后30個商品的標簽后,進行for循環遍歷,每次遍歷都把價格和名字一一對應地添加到價格列表和名字列表里。並且使用''.join(seq)把后30個商品的名字處理好。 71 ''' 72 73 def get_informatiion_by_interface(): 74 import requests 75 from lxml import etree 76 import re 77 for page in range(1,10,2): 78 print('-------------------------------------------------------------------------------------------------------------------------') 79 # url 是每一頁網頁源代碼的url。 80 url = 'https://search.jd.com/s_new.php?keyword=%E5%A4%A7%E5%9C%B0%E7%93%9C&qrst=1&wq=%E5%A4%A7%E5%9C%B0%E7%93%9C&stock=1&page=' + str(page) + '&s=1&click=0' 81 82 # 請求的header頭部增加瀏覽器的cookie信息的目的是為了使得我們抓取到的商品排序和我們用瀏覽器打開頁面后商品的排序是一樣的 83 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36', 84 'referer': 'https://search.jd.com/Search?keyword=%E5%A4%A7%E5%9C%B0%E7%93%9C&qrst=1&wq=%E5%A4%A7%E5%9C%B0%E7%93%9C&stock=1&page=1&s=1&click=0', 85 'cookie': '3AB9D23F7A4B3C9B=2UDPAMUVVAOX4434BC7I2ZLURIPLLIIUQP4YPLIOTU664VIP7KSLA6MAK6OQKGJHRZZDQ3DYSFK5XDBNHFCU6KJB6M; __jda=122270672.15933569519401053893576.1593356952.1593356952.1593356952.1; __jdv=122270672|direct|-|none|-|1593356951941; __jdc=122270672; __jdu=15933569519401053893576; shshshfp=570e85b8b983f561323d6ce789eb70fd; shshshfpa=ca3ed469-1333-824a-e055-0077f782a98a-1593356953; shshshfpb=vLxmwxHcieTu9rJHld9YGrQ%3D%3D; areaId=20; ipLoc-djd=20-1818-1824-0; __jdb=122270672.3.15933569519401053893576|1.1593356952; shshshsID=b47f5b4faadb933f4f6c6bc34f7c587a_3_1593357253227'} 86 87 price_list = [] 88 name_list = [] 89 html_befor30 = requests.get(url, headers=headers) 90 html_befor30 = etree.HTML(html_befor30.text) 91 shangpins_befor30 = html_befor30.xpath('//*[@id="J_goodsList"]/ul//li/div') 92 for shangpin in shangpins_befor30: 93 price = shangpin.xpath('div[2]/strong/i//text()') 94 name = shangpin.xpath('div[3]/a/em//text()') 95 price_list.append(price[0]) 96 name_list.append(''.join(name)) 97 98 #后30個數據信息 99 # 對每一頁的網頁源代碼進行請求,目的是為了使用正則表達式匹配后30個商品對應的30個數字。 100 html_re = requests.get(url,headers=headers) 101 pattern = 'data-sku="(\d+)' 102 id_number = re.findall(pattern,html_re.text) 103 # 匹配到數字后使用字符串拼接的方式構造一個完整的get接口的url。使用set方法把匹配到重復的數字去重。 104 id_number = ','.join(set(id_number)) 105 urls = 'https://search.jd.com/s_new.php?keyword=%E5%A4%A7%E5%9C%B0%E7%93%9C&qrst=1&wq=%E5%A4%A7%E5%9C%B0%E7%93%9C&stock=1&page=' + str(page+1) + '&s=31&scrolling=y&log_id=1593366515600.6909&tpl=1_M&isList=0&show_items=' + id_number 106 107 #請求時必須要加上headers頭,不然會觸發登錄機制。 108 html_later30 = requests.get(urls,headers=headers) 109 html_later30 = etree.HTML(html_later30.text) 110 shangpins_later30 = html_later30.xpath('//li/div') 111 for shangpin in shangpins_later30: 112 price = shangpin.xpath('div[2]/strong/i//text()') 113 name = shangpin.xpath('div[3]/a/em//text()') 114 price_list.append(price[0]) 115 name_list.append(''.join(name)) 116 117 #打印60個數據信息 118 for (price,name) in zip(price_list,name_list): 119 print(price,name) 120 121 if __name__ == '__main__': 122 get_informatiion_by_interface() 123 get_informations_by_selenium()