開源實踐 | 攜程在OceanBase的探索與實踐
需要準備的東西:
python基礎, html, css
web請求過程分析
- 伺服器的渲染:在伺服器那邊直接把資料和html整合在一起,統一返回給瀏覽器
- 在頁面原始碼中可以看到資料
- 客戶端渲染:
- 第一次請求只要一個html骨架,第二次請求拿到資料,進行資料展示
- 在頁面原始碼中看不到資料
HTTP協議(超文字傳輸協議)
Http協議吧一條資訊分為三大塊內容,無論是請求還是相應都是三大塊
請求:
1. 請求行 -> 請求方式 請求url地址 協議
2. 請求頭 -> 放一些伺服器要使用的附加資訊
3. 請求體 -> 一般放一些請求引數
相應
1. 狀態行 -> 協議 狀態碼 2. 響應頭 -> 放一些客戶端要使用的一些附加資訊 3. 響應體 -> 伺服器返回的真正客戶端要使用的內容(Html, json)等
請求頭中最常見的一些重要內容(爬蟲需要):
- User-Agent:請求載體的身份標識(用啥傳送的請求)
- Referer:防盜鏈(這次請求是從哪個頁面來的,反爬會用到)
- cookie:本地字串資料資訊(使用者登入資訊,反爬的token)
響應頭中一些重要的內容
- cookie:本地字串資料資訊(使用者登入資訊,反爬的token)
- 各種神奇的莫名存在的字串(這個需要經驗,一般都是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表示式
-
findall:匹配字串中所有的複合正則表示式的內容
- lst = re.findall(r"\d+","我的電話號碼是:10086, 我女朋友的電話號碼是:10010“)
- print(list) ====== ['10086', '10010'] // 使用findall返回的是一個列表
- lst = re.findall(r"\d+","我的電話號碼是:10086, 我女朋友的電話號碼是:10010“)
-
finditer:匹配字串中所有的內容[返回一個迭代器],從迭代器中獲取每個元素使用.group()
-
it = re.finditer(e"\d+", "我的電話號碼是:10086, 我女朋友的電話號碼是:10010“)
for i in it: print(i.group)
-
-
search,找到一個結果就返回,返回的結果是match物件,從中拿資料需要使用.group
- s = re.search(r"\d+","我的電話號碼是:10086, 我女朋友的電話號碼是:10010“)
- print(s.group) ======= 10086// 只返回一個結果
-
match 是從頭開始匹配
- s = re.match(r"\d+","我的電話號碼是:10086, 我女朋友的電話號碼是:10010")
- print(s.group) === 會報錯 ,因為s為空
- s = re.match(r"\d+","10086, 我女朋友的電話號碼是:10010“)
- print(s.group) ==== 10086
-
預載入正則表示式(將正則表示式放在變數中)
obj = re.compile(r"\d+") ret = obj.finditer("我的電話號碼是:10086, 我女朋友的電話號碼是:10010") for it in ret: print(it.group)
-
通過正則表示式獲取其中一部分東西
- 獲取方法 :(?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")) // 輸出結果 郭麒麟 宋鐵 大聰明 範思哲 喜羊羊
-
當我們在使用requests請求的時候如果報錯的話,出現
exceptions.SSLError:HTTPSConnectionPool 這種情況,一般是requests函式內部檢查出錯,我們可以使用:
requests.get(url, verify=Flase) // verify = Flase 去掉安全驗證
bs4解析
-
把頁面原始碼交給BeautifulSoup進行處理,生成bs物件
page = BeautifulSoup(resp.text,"html.parser")
-
從bs物件中查詢資料
find(標籤,屬性=值) find_all(標籤,屬性=值) # 當我們使用屬性 = 值的時候屬性的名稱可能和python中的關鍵字重名,這樣會報錯 # 現在給出一下解決方法 table = page.find("table", class_="hq_table") # 這裡class屬性名就和python中的關鍵字重複了,我們可以加下劃線 # 另一種解決方法 table = page.fine("table", attrs={"class" : "hq_table"}) # 這種寫法和上面的相同
-
".text"方法可以獲取標籤中包裹著的文字
-
".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中出現的可能是動態載入的