爬蟲簡介
網(wǎng)絡(luò)爬蟲(又被稱為網(wǎng)頁蜘蛛倡勇,網(wǎng)絡(luò)機(jī)器人山害,在FOAF社區(qū)中間,更經(jīng)常的稱為網(wǎng)頁追逐者)冰木,是一種按照一定的規(guī)則穷劈,自動地抓取萬維網(wǎng)信息的程序或者腳本。另外一些不常使用的名字還有螞蟻踊沸、自動索引歇终、模擬程序或者蠕蟲。
其實逼龟,說白了就是爬蟲可以模擬瀏覽器的行為做你想做的事评凝,訂制化自己搜索和下載的內(nèi)容,并實現(xiàn)自動化的操作审轮。比如瀏覽器可以下載小說肥哎,但是有時候并不能批量下載,那么爬蟲的功能就有用武之地了疾渣。
實現(xiàn)爬蟲技術(shù)的編程環(huán)境有很多種篡诽,Java,Python榴捡,C++等都可以用來爬蟲杈女。但是博主選擇了Python,相信很多人也一樣選擇Python吊圾,因為Python確實很適合做爬蟲达椰,豐富的第三方庫十分強(qiáng)大,簡單幾行代碼便可實現(xiàn)你想要的功能项乒,更重要的啰劲,Python也是數(shù)據(jù)挖掘和分析的好能手。
requests庫
Requests 唯一的一個非轉(zhuǎn)基因的 Python HTTP 庫檀何,人類可以安全享用蝇裤。
警告:非專業(yè)使用其他 HTTP 庫會導(dǎo)致危險的副作用廷支,包括:安全缺陷癥、冗余代碼癥栓辜、重新發(fā)明輪子癥恋拍、啃文檔癥、抑郁藕甩、頭疼施敢、甚至死亡。
Requests 允許你發(fā)送純天然狭莱,植物飼養(yǎng)的 HTTP/1.1 請求僵娃,無需手工勞動。你不需要手動為 URL 添加查詢字串贩毕,也不需要對 POST 數(shù)據(jù)進(jìn)行表單編碼悯许。Keep-alive 和 HTTP 連接池的功能是 100% 自動化的,一切動力都來自于根植在 Requests 內(nèi)部的 urllib3辉阶。
各種請求方式
requests里提供個各種請求方式
import requests
requests.post("http://httpbin.org/post")
requests.put("http://httpbin.org/put")
requests.delete("http://httpbin.org/delete")
requests.head("http://httpbin.org/get")
requests.options("http://httpbin.org/get")
基本GET請求
import requests
response = requests.get('http://httpbin.org/get')
print(response.text)
帶參數(shù)的GET請求
import requests
response = requests.get("http://httpbin.org/get?name=zhaofan&age=23")
print(response.text)
import requests
data = {
"name":"zhaofan",
"age":22
}
response = requests.get("http://httpbin.org/get",params=data)
print(response.url)
print(response.text)
上述兩種的結(jié)果是相同的先壕,通過params參數(shù)傳遞一個字典內(nèi)容,從而直接構(gòu)造url
注意:第二種方式通過字典的方式的時候谆甜,如果字典中的參數(shù)為None則不會添加到url上
基本POST請求
通過在發(fā)送post請求時添加一個data參數(shù)垃僚,這個data參數(shù)可以通過字典構(gòu)造成,這樣
對于發(fā)送post請求就非常方便
import requests
data = {
"name":"zhaofan",
"age":23
}
response = requests.post("http://httpbin.org/post",data=data)
print(response.text)
同樣的在發(fā)送post請求的時候也可以和發(fā)送get請求一樣通過headers參數(shù)傳遞一個字典類型的數(shù)據(jù)
響應(yīng)
我們可以通過response獲得很多屬性规辱,例子如下
import requests
response = requests.get("http://www.baidu.com")
print(type(response.status_code),response.status_code)
print(type(response.headers),response.headers)
print(type(response.cookies),response.cookies)
print(type(response.url),response.url)
print(type(response.history),response.history)
獲取cookie
import requests
response = requests.get("http://www.baidu.com")
print(response.cookies)
for key,value in response.cookies.items():
print(key+"="+value)
會話維持
cookie的一個作用就是可以用于模擬登陸谆棺,做會話維持
import requests
s = requests.Session()
s.get("http://httpbin.org/cookies/set/number/123456")
response = s.get("http://httpbin.org/cookies")
print(response.text)
證書驗證
現(xiàn)在的很多網(wǎng)站都是https的方式訪問,所以這個時候就涉及到證書的問題
import requests
response = requests.get("https:/www.12306.cn")
print(response.status_code)
import requests
from requests.packages import urllib3
urllib3.disable_warnings()
response = requests.get("https://www.12306.cn",verify=False)
print(response.status_code)
代理設(shè)置
import requests
proxies= {
"http":"http://127.0.0.1:9999",
"https":"http://127.0.0.1:8888"
}
response = requests.get("https://www.baidu.com",proxies=proxies)
print(response.text)
超時設(shè)置
通過timeout參數(shù)可以設(shè)置超時的時間
認(rèn)證設(shè)置
如果碰到需要認(rèn)證的網(wǎng)站可以通過requests.auth模塊實現(xiàn)
import requests
from requests.auth import HTTPBasicAuth
response = requests.get("http://120.27.34.24:9001/",auth=HTTPBasicAuth("user","123"))
print(response.status_code)
import requests
response = requests.get("http://120.27.34.24:9001/",auth=("user","123"))
print(response.status_code)
xpath解析Dom樹
XPath 是一門在 XML 文檔中查找信息的語言罕袋。
XPath 是 XSLT 中的主要元素改淑。
XQuery 和 XPointer 均構(gòu)建于 XPath 表達(dá)式之上
XPath總體來說功能很強(qiáng)大,而且查找效率別正則表達(dá)式要好很多浴讯,這里我們只用到一部分常用功能朵夏。
選取節(jié)點
XPath 使用路徑表達(dá)式在 XML 文檔中選取節(jié)點。節(jié)點是通過沿著路徑或者 step 來選取的榆纽。 下面列出了最有用的路徑表達(dá)式:
在下面的表格中仰猖,我們已列出了一些路徑表達(dá)式以及表達(dá)式的結(jié)果:
謂語(Predicates)
謂語用來查找某個特定的節(jié)點或者包含某個指定的值的節(jié)點。
謂語被嵌在方括號中奈籽。
在下面的表格中饥侵,我們列出了帶有謂語的一些路徑表達(dá)式,以及表達(dá)式的結(jié)果:
選取未知節(jié)點
XPath 通配符可用來選取未知的 XML 元素衣屏。
在下面的表格中躏升,我們列出了一些路徑表達(dá)式,以及這些表達(dá)式的結(jié)果:
選取若干路徑
通過在路徑表達(dá)式中使用"|"運算符狼忱,您可以選取若干個路徑煮甥。
在下面的表格中盗温,我們列出了一些路徑表達(dá)式藕赞,以及這些表達(dá)式的結(jié)果:
模擬GitHub登錄獲取個人信息
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Created by master on 2018/7/2 16:21.
import requests
import re
from lxml import etree
user_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh,en;q=0.9,zh-CN;q=0.8',
}
# html文檔下載模塊
def download_html(user, pwd):
login_url = 'https://github.com/login'
# 使用session自動處理cookies
session = requests.Session()
# 獲取authenticity_token
response = session.get(login_url, headers=user_headers, verify=False)
pattern = re.compile(r'<input type="hidden" name="authenticity_token" value="(.*)" />')
authenticity_token = pattern.findall(response.text)[0]
# 登錄參數(shù)
login_data = {
'commit': 'Sign in',
'utf8': '?',
'authenticity_token': authenticity_token, 'login': user,
'password': pwd
}
# 登錄
session_url = 'https://github.com/session'
response = session.post(session_url, headers=user_headers, data=login_data, verify=False)
pattern = re.compile(r'Incorrect username or password')
if pattern.findall(response.text): # 密碼錯誤
print("賬號或密碼錯誤成肘!")
return
else:
# 獲取user_id
pattern = re.compile(r'Signed in as <strong class="css-truncate-target">(.*)</strong>')
user_id = pattern.findall(response.text)[0]
# 請求個人信息頁面
response = session.get("https://github.com/" + user_id, headers=user_headers, verify=False)
return etree.HTML(response.text)
# 信息解析模塊
def parse_html(html):
if not html:
return
your_avatar = html.xpath("http://img[@class='avatar width-full rounded-2']/@src")[0]
your_nickname = html.xpath("http://span[@class='p-name vcard-fullname d-block overflow-hidden']/text()")[0]
your_user_id = html.xpath("http://span[@class='p-nickname vcard-username d-block']/text()")[0]
your_repositories = html.xpath("http://a[@class='UnderlineNav-item '][@title='Repositories']/span/text()")[0]
your_stars = html.xpath("http://a[@class='UnderlineNav-item '][@title='Stars']/span/text()")[0]
your_follows = html.xpath("http://a[@class='UnderlineNav-item '][@title='Followers']/span/text()")[0]
your_following = html.xpath("http://a[@class='UnderlineNav-item '][@title='Following']/span/text()")[0]
print("your avatar url: %s" % your_avatar)
print("your nick name: %s" % trim(your_nickname))
print("your user id: %s" % trim(your_user_id))
print("your repositories count: %s" % trim(your_repositories))
print("your starts count: %s" % trim(your_stars))
print("your follows count: %s" % trim(your_follows))
print("your fans count: %s" % trim(your_following))
# 去掉空格和換行
def trim(txt):
return txt.strip().replace("\n", "")
if __name__ == '__main__':
username = input("請輸入您的GitHub賬號:")
password = input("請輸入您的GitHub密碼:")
html_doc = download_html(username, password)
parse_html(html_doc)
輸出
請輸入您的GitHub賬號:**********
請輸入您的GitHub密碼:**********
your avatar url: https://avatars2.githubusercontent.com/u/11495586?s=460&v=4
your nick name: lxy
your user id: lxygithub
your repositories count: 29
your starts count: 60
your follows count: 2
your fans count: 6