1. 程式人生 > 其它 >開源實踐 | 攜程在OceanBase的探索與實踐

開源實踐 | 攜程在OceanBase的探索與實踐

需要準備的東西:

python基礎, html, css

web請求過程分析

  1. 伺服器的渲染:在伺服器那邊直接把資料和html整合在一起,統一返回給瀏覽器
    • 在頁面原始碼中可以看到資料
  2. 客戶端渲染:
    • 第一次請求只要一個html骨架,第二次請求拿到資料,進行資料展示
    • 在頁面原始碼中看不到資料

HTTP協議(超文字傳輸協議)

Http協議吧一條資訊分為三大塊內容,無論是請求還是相應都是三大塊

請求:

1. 請求行 -> 請求方式	請求url地址	協議
2. 請求頭 -> 放一些伺服器要使用的附加資訊
3. 請求體 -> 一般放一些請求引數

相應

1. 狀態行 -> 協議 狀態碼
2. 響應頭 -> 放一些客戶端要使用的一些附加資訊
3. 響應體 -> 伺服器返回的真正客戶端要使用的內容(Html, json)等

請求頭中最常見的一些重要內容(爬蟲需要):

  1. User-Agent:請求載體的身份標識(用啥傳送的請求)
  2. Referer:防盜鏈(這次請求是從哪個頁面來的,反爬會用到)
  3. cookie:本地字串資料資訊(使用者登入資訊,反爬的token)

響應頭中一些重要的內容

  1. cookie:本地字串資料資訊(使用者登入資訊,反爬的token)
  2. 各種神奇的莫名存在的字串(這個需要經驗,一般都是token,放著各種攻擊和反爬)

請求方式:

​ GET:顯示提交

​ POST:隱式提交

資料解析概述

正則表示式

Regular Expression,正則表示式,一種使用表示式的方式對字串進行匹配的語法規則

我們抓取到的網頁原始碼本質上就是一個超長的字串,想從裡面提取內容,則正則再適合不過了

正則優點:速度快,效率高,準確性高

正則的缺點:新手上手難度有點高

不過只要掌握了正則編寫的邏輯關係,寫出一個提取網頁內容的正則其實並不複雜

正則語法:使用元字元進行排列組合用來匹配字串,可以在正則表示式線上測試

元字元:具有固定含義的特殊符號

常用元字元

1.	.	匹配除換行符以外的任意字元
2.	\w	匹配字母或數字或下劃線
3.	\s	匹配任意的空白字元
4.	\d	匹配數字
5.	\n	匹配一個換行符
6.	\t	匹配一個換行符
7.	^	匹配字串的開始
8.	$	匹配字串的結尾
9.	\W	匹配非字母或數字或下劃線
10.	\D	匹配非數字
11.	\S	匹配非空白字元
12.	a|b	匹配字元a或字元b
13.	()	匹配括號內的表示式,也表示一個組
14.	[...]	匹配字元組中的字元 // [a-zA-Z0-9]匹配a-z和A-Z和0-9之間的字元
15.	[^...]	匹配處理除字元陣列中字元的所有字元

一般一個元字元表示一個字元

一般和$配合使用:\d\d\d$

量詞:控制前面的元字元出現的次數

*	重複零次或更多次
+	重複一次或更多次
?	重複零次或一次
{n}	重複n次
{n,}	重複n次或更多次
{n,m}	重複n到m次

貪婪匹配和惰性匹配

.*	貪婪匹配
.*?	惰性匹配

re表示式

  1. findall:匹配字串中所有的複合正則表示式的內容

    • lst = re.findall(r"\d+","我的電話號碼是:10086, 我女朋友的電話號碼是:10010“)
      • print(list) ====== ['10086', '10010'] // 使用findall返回的是一個列表
  2. finditer:匹配字串中所有的內容[返回一個迭代器],從迭代器中獲取每個元素使用.group()

    1. it = re.finditer(e"\d+", "我的電話號碼是:10086, 我女朋友的電話號碼是:10010“)

      for i in it:
      	print(i.group)
      
  3. search,找到一個結果就返回,返回的結果是match物件,從中拿資料需要使用.group

    • s = re.search(r"\d+","我的電話號碼是:10086, 我女朋友的電話號碼是:10010“)
    • print(s.group) ======= 10086// 只返回一個結果
  4. match 是從頭開始匹配

    • s = re.match(r"\d+","我的電話號碼是:10086, 我女朋友的電話號碼是:10010")
    • print(s.group) === 會報錯 ,因為s為空
    • s = re.match(r"\d+","10086, 我女朋友的電話號碼是:10010“)
    • print(s.group) ==== 10086
  5. 預載入正則表示式(將正則表示式放在變數中)

    obj = re.compile(r"\d+")
    
    ret = obj.finditer("我的電話號碼是:10086, 我女朋友的電話號碼是:10010")
    for it in ret:
        print(it.group)
    
  6. 通過正則表示式獲取其中一部分東西

    • 獲取方法 :(?P<分組名字>正則表示式) 這樣可以單獨的從正則匹配的內容中進一步提取內容
    s = """
        <div class='jay'><span id='1'>郭麒麟</span></div>
    	<div class='jj'><span id='2'>宋鐵</span></div>
    	<div class='jolin'><span id='3'>大聰明</span></div>
    	<div class='sylar'><span id='4'>範思哲</span></div>
    	<div class='tory'><span id='5'>喜羊羊</span></div>
    """
    
    # 預載入正則表示式
    obj = re.compile(r"<div class='.*?'><span id='\d'>(?P<name>.*?)</span></div>")
    result = obj.finditer(s)
    for it in result:
        print(it.group("name"))
    // 輸出結果
    郭麒麟
    宋鐵
    大聰明
    範思哲
    喜羊羊
    
    
  7. 當我們在使用requests請求的時候如果報錯的話,出現

    exceptions.SSLError:HTTPSConnectionPool 這種情況,一般是requests函式內部檢查出錯,我們可以使用:

    requests.get(url, verify=Flase) // verify = Flase 去掉安全驗證

bs4解析

  1. 把頁面原始碼交給BeautifulSoup進行處理,生成bs物件

    page = BeautifulSoup(resp.text,"html.parser")

  2. 從bs物件中查詢資料

    find(標籤,屬性=值)
    find_all(標籤,屬性=值)
    # 當我們使用屬性 = 值的時候屬性的名稱可能和python中的關鍵字重名,這樣會報錯
    # 現在給出一下解決方法
    table = page.find("table", class_="hq_table") # 這裡class屬性名就和python中的關鍵字重複了,我們可以加下劃線
    # 另一種解決方法
    table = page.fine("table", attrs={"class" : "hq_table"}) # 這種寫法和上面的相同
    
  3. ".text"方法可以獲取標籤中包裹著的文字

  4. ".get('herf')" 獲取標籤的屬性

xpath解析

xpath 是在XML文件中搜索內容的一門語言

html是XML的一個子集

Xpath尋找方式是從父節點,到子節點這樣的方式尋找

<book>
	<id>1</id>
	<name>zhang</name>
	<author>
		<nick>周大強</nick>
		<nick>周芷若</nick>
		<div>
			<nick>阿布</nick>
			<nick>安安</nick>
		</div>
		<span>
			<nick>大胖</nick>
		</span>
	</author>
</book>
# 尋找方式: /book/author/ nick 其中 “/” 表示層級關係,第一個 /  表示從根節點開始尋找   / 表示獲取父節點的(兒子)
#  /book/author/ nick/text() 這樣就獲取了nick中的文字了   text()表示獲取文字
# 獲取author裡面的所有nick只通過  /  這個符是不行的 / 符只能一層層尋找不能夠跨層尋找
# /book/author//nick/text()   這樣就拿到author裡面所有的nick了   //  表示獲取父節點的後代(子孫)
# /book/author/*/nick/text()  這樣就拿到author裡面隔一個標籤裡面的nick了  * 萬用字元(任意節點)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <ul>
    <li><a href="www.baidu.com">百度</a></li>
    <li><a href="www.google.com">谷歌</a></li>
    <li><a href="www.sougou.com">搜狗</a></li>
  </ul>
  <ol>
    <li><a href="feiji">飛機</a></li>
    <li><a href="dapao">大炮</a></li>
    <li><a href="huoche">火車</a></li>
  </ol>
  <div class="job">李嘉誠</div>
  <div class="common">胡辣湯</div>
</body>
</html>
# result = tree.xpath('/html')
# result = tree.xpath('/html/body/ul/li/a/text()')  尋找ul/li/a標籤中所有的文字
# result = tree.xpath('/html/body/ul/li[1]/a/text()')  尋找ul/li中第一個li標籤中的a標籤 xpath順序是從1開始的
# 下面這是個尋找ul/li/a標籤中href為“dapao”的標籤的文字 [@xxx = xxx] 表示屬性的篩選
# result = tree.xpath('html/body/ol/li/a/[@href = "dapao"]/text()') 
ol_li_list = tree.xpath("html/body/ol/li")
for li in ol_li_list:
	# 從每個li中提取到文字資訊
	result = li.xpath("./a/text()") # 在li中繼續尋找 使用 " . " 這個表示當前目錄 
	result2 = li.xpaht('.a/@href')   # 拿到屬性值@ 屬性

requests 進階概述

模擬瀏覽器登入 ---> 處理cookie

# 登入  --> 得到cookie
# 帶著cookie 去請求後臺頁面  --> 獲取只有登入才能訪問的頁面

# 我們需要把上面的步驟連起來,保證cookie不會丟失
# 這裡我們就可使用session進行請求 -> session請求你可以認為是一連串的請求,在這個過成功cookie,不會丟失

import requests

data = {
	"loginName":""
	"password":""
}

session = requsets.session()
# 1. 登入
url = "...."
# 通過session來請求頁面,這樣的話session就會記住cookie,方便我們下一步訪問
resp = session.post(url, data = data)
# print(resp.cookies)   # 看cookie

# 2.拿書架上的資料
# resp = requests.get(url = "...")  !! 千萬不要這樣寫,因為這樣會向瀏覽器從新發送請求,會丟失cookie訪問失敗
# 我們使用session 來進行訪問:
resp = session.get("....")
print(resp.json()) 

防盜鏈處理 --->抓取梨視訊資料

防盜鏈的用途:就是在你訪問這個頁面之前,你必須訪問referer指向的網址

頁面原始碼和F12中出現的程式碼可能是不同的,F12中出現的可能是動態載入的

代理 ---->防止別封ip