本文是讀者投稿第二篇,如果你也想投稿,可以後臺聯系我 作者:parkson 知乎:https://www.zhihu.com/people/parkson-19/activities 喜歡的可以關注下,點擊原文閱讀可直達。
本文的大致路線
首先列舉出一些python中爬蟲常用的庫,用之前需要先下載好,本文假設你已經安裝好相應的庫。
下載庫:
0、Urllib庫
1、requests 做請求的時候用到
2、selenium 自動化會用到
解析庫:
3、正則匹配re 解析網頁
4、lxml第三方庫,用於Xpath
5、beautifulSoup 解析網頁
6、pyquery 網頁解析庫和beautifulSoup類似
數據庫操作庫:
7、pymysql 操作mysql數據的
8、pymongo 操作MongoDB數據庫
9、redis 非關係型數據庫
10、jupyter 在線記事本
一、簡單理解Ajax
1、AJAX是一種技術,是一種用於創建快速動態網頁的技術;不是新的編程語言,而是一種使用現有標準的新方法。
2、AJAX=Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)
3、AJAX 是與服務器交換數據並更新部分網頁的藝術,在不重新加載整個頁面的情況下,對網頁的某部分進行更新。傳統的網頁(不使用AJAX)如果需要更新內容,必需重載整個網頁。
4、Ajax技術的核心是XMLHttpRequest對象(簡稱XHR,即AJAX創建XMLHttpRequest對象,並向服務器發送請求),可以通過使用XHR對象獲取到服務器的數據,然後再通過DOM將數據插入到頁面中呈現(AJAX加載出來的數據通過瀏覽器渲染顯示)。雖然名字中包含XML,但Ajax通訊與數據格式無關(是一種網頁製作中的一種方法、技術),所以我們的數據格式可以是XML或JSON等格式。
二、爬取AJAX動態加載網頁案例
爬蟲,簡單點說就是自動從網上下載自己感興趣的信息,一般分爲兩個步驟,下載,解析。
Ajax一般返回的是json格式數據,直接使用requests對ajax地址進行post或get(下載),返回json格式數據,解析json數據即可得到想要獲取的信息(解析)。
我們如果使用 AJAX 加載的動態網頁,怎麼爬取裏面動態加載的內容呢?一般有兩種方法:
方法一、通過selenium模擬瀏覽器抓取
方法二、通過瀏覽器審查元素解析地址
案例一、URL不變,選項卡中二次請求的URL以一定規律變化
以豆瓣電影爲例:https://movie.douban.com/tag/#/?sort=T&range=0,10&tags=%E5%8A%B1%E5%BF%97,點擊 加載更多 刷新網頁。
方法一、通過selenium模擬瀏覽器抓取,Beautiful Soup解析網頁
這裏給出了設定一定的點擊次數和一直不斷點擊加載更多兩種請求方式
##設置一定的點擊次數 from bs4 import BeautifulSoup from selenium import webdriver import time import re browser = webdriver.Chrome()###版本 68.0.3440.106(正式版本) (64 位) browser.get('https://movie.douban.com/tag/#/?sort=T&range=0,10&tags=') browser.implicitly_wait(3)##瀏覽器解釋JS腳本是需要時間的,但實際上這個時間並不好確定,如果我們手動設定時間間隔的話,設置多了浪費時間,設置少了又會丟失數據 ##implictly_wait函數則完美解決了這個問題,給他一個時間參數,它會只能等待,當js完全解釋完畢就會自動執行下一步。 time.sleep(3) browser.find_element_by_xpath('//*[@id="app"]/div/div[1]/div[1]/ul[4]/li[6]/span').click()###自動選擇勵志電影類型 i = 0 for i in range(5):##這裏設置點擊5次“加載更多” browser.find_element_by_link_text("加載更多").click() time.sleep(5)###如果網頁沒有完全加載,會出現點擊錯誤,會點擊到某個電影頁面,所以加了一個睡眠時間。 ##browswe.page_source是點擊5次後的源碼,用Beautiful Soup解析源碼 soup = BeautifulSoup(browser.page_source, 'html.parser') items = soup.find('div', class_=re.compile('list-wp')) for item in items.find_all('a'): Title = item.find('span', class_='title').text Rate = item.find('span', class_='rate').text Link = item.find('span',class_='pic').find('img').get('src') print(Title,Rate,Link) ------------------------------------------------------------------------------------------------ ###一直不斷點擊,直到加載完全 from bs4 import BeautifulSoup from selenium import webdriver import time import re browser = webdriver.Chrome()###版本 68.0.3440.106(正式版本) (64 位) browser.get('https://movie.douban.com/tag/#/?sort=T&range=0,10&tags=') browser.implicitly_wait(3) time.sleep(3) browser.find_element_by_xpath('//*[@id="app"]/div/div[1]/div[1]/ul[4]/li[6]/span').click()###自動選擇勵志電影類型 soup = BeautifulSoup(browser.page_source, 'html.parser') while len(soup.select('.more'))>0:##soup.select(),返回類型是 list,判斷只要長度大於0,就會一直不斷點擊。 browser.find_element_by_link_text("加載更多").click() time.sleep(5)###如果網頁沒有完全加載,會出現點擊錯誤,會點擊到某個電影頁面,所以加了一個睡眠時間。 soup = BeautifulSoup(browser.page_source, 'html.parser') ##將 加載更多 全部點擊完成後,用Beautiful Soup解析網頁源代碼 items = soup.find('div', class_=re.compile('list-wp')) for item in items.find_all('a'): Title = item.find('span', class_='title').text Rate = item.find('span', class_='rate').text Link = item.find('span', class_='pic').find('img').get('src') print(Title, Rate, Link)
方法二、依據選項卡中URL規律直接構造二次請求的URL
網頁是通過ajax加載,加載一次顯示20部電影。
點擊加載更多
可以從Network選項卡中發現,多了一個new_search,就是點擊加載更多後重新加載的頁面,對比幾個new_search會發現Request URL的末尾start=i,i一直是20的倍數,因此可以直接寫一個循環爬取多頁面的電影信息。
import requests from requests.exceptions import RequestException import time import csv import json headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'} def get_one_page(url): try: response = requests.get(url,headers=headers) if response.status_code == 200: return response.json()##將返回的json數據轉換爲python可讀的字典數據,.json是requests庫自帶的函數。 return None except RequestException: print("抓取失敗") def parse_one_page(d): try: datum = d['data'] for data in datum: yield{ 'Title':data['title'], 'Director':data['directors'], 'Actors':data['casts'], 'Rate':data['rate'], 'Link':data['url'] } if data['Title','Director','Actors','Rate','Link'] == None: return None except Exception: return None def main(): for i in range(10):###這裏就抓取10個網頁,如果需求更多數據,將將數字改更大些即可。 url = 'https://movie.douban.com/j/new_search_subjects?sort=T&range=0,10&tags=%E5%8A%B1%E5%BF%97&start={}'.format(i*20) d = get_one_page(url) print('第{}頁抓取完畢'.format(i+1)) for item in parse_one_page(d): print(item) ##將輸出字典依次寫入csv文件中 with open('Movie.csv', 'a', newline='',encoding='utf-8') as f: # file_path 是 csv 文件存儲的路徑,默認路徑 fieldnames = ['Title', 'Director', 'Actors', 'Rate', 'Link'] writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() for item in parse_one_page(d): writer.writerow(item) if __name__=='__main__': main()
案例二、URL不變,選項卡中二次請求的URL沒有規律
以CSDN網站爲例,抓取CSDN首頁文章列表:CSDN-專業IT技術社區下拉時URL不變,選項卡中二次請求的URL沒有規律,網頁 下拉 刷新。
方法一、通過selenium模擬瀏覽器抓取,正則表達式解析網頁
from selenium import webdriver import re import time browser = webdriver.Chrome() browser.get('https://www.csdn.net/') browser.implicitly_wait(10) i = 0 for i in range(5):###設置下拉5次,如果想獲取更多信息,增加下拉次數即可 browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')##下拉,execute_script可以將進度條下拉到最底部 time.sleep(5)##睡眠一下,防止網絡延遲,卡頓等 data = [] pattern = re.compile('<li.*?blog".*?>.*?title">.*?<a.*?>(.*?)</a>.*?<dd.*?name">.*?<a.*?blank">(.*?)</a>' '.*?<span.*?num">(.*?)</span>.*?text">(.*?)</span>.*?</li>',re.S) items = re.findall(pattern,browser.page_source)##這裏網頁源代碼爲下拉5次後的代碼 for item in items: data.append({ 'Title':item[0].strip(), 'Author' : item[1].strip(), 'ReadNum' : item[2] + item[3] }) print(data)
方法二、通過瀏覽器審查元素解析真實地址
import requests headers = {'cookie':'uuid_tt_dd=3844871280714138949_20171108; kd_user_id=e61e2f88-9c4f-4cf7-88c7-68213cac17f7; UN=qq_40963426; BT=1521452212412; Hm_ct_6bcd52f51e9b3dce32bec4a3997715ac=1788*1*PC_VC; smidV2=20180626144357b069d2909d23ff73c3bc90ce183c8c57003acfcec7f57dd70; __utma=17226283.14643699.1533350144.1533350144.1534431588.2; __utmz=17226283.1533350144.1.1.utmcsr=zhuanlan.zhihu.com|utmccn=(referral)|utmcmd=referral|utmcct=/p/39165199/edit; TY_SESSION_ID=f49bdedd-c1d4-4f86-b254-22ab2e8f02f6; ViewMode=contents; UM_distinctid=165471259cb3e-02c5602643907b-5d4e211f-100200-165471259cc86; dc_session_id=10_1534471423488.794042; dc_tos=pdlzzq; Hm_lvt_6bcd52f51e9b3dce32bec4a3997715ac=1534515139,1534515661,1534515778,1534515830; Hm_lpvt_6bcd52f51e9b3dce32bec4a3997715ac=1534515830; ADHOC_MEMBERSHIP_CLIENT_ID1.0=d480c872-d4e9-33d9-d0e5-f076fc76aa83', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'} def get_page(): r =requests.get('https://www.csdn.net/api/articles?type=more&category=home&shown_offset=1534516237069160',headers=headers) d=r.json()#一般ajax返回的都是json格式數據,將返回的數據json格式化,.json()是requests庫自帶函數 articles = d['articles']#字典形式 for article in articles: yield { 'article':article['title'], 'Link':article['user_url'], 'View':article['views'] } for i in get_page(): print(i) ##這裏應該有關於抓取不同頁文章標題的操作,但是還沒有解決。
案例二參考鏈接:https://zhuanlan.zhihu.com/p/35682031
備註:CSDN爬取基本諮詢需要注意都會有一個置頂的信息,在使用selenium+Beautiful Soup或者xpath解析時,需要單獨注意,不然代碼一直報錯。
不管對於靜態的網頁還是動態的網頁,爬蟲的核心就是下載與解析。