urllib庫,它是Python內置的HTTP請求庫。它包含4個模塊:html
request:它是最基本的HTTP請求模塊,能夠用來模擬發送請求。html5
error:異常處理模塊,若是出現請求錯誤,咱們能夠捕獲這些異常,而後進行重試或其餘操做以保證程序不會意外終止。node
parse:一個工具模塊,提供了許多URL處理方法,好比拆分、解析、合併等。python
robotparser:主要是用來識別網站的robots.txt文件,而後判斷哪些網站能夠爬,哪些網站不能夠爬,它其實用得比較少。正則表達式
request模塊主要功能:構造HTTP請求,利用它能夠模擬瀏覽器的一個請求發起過程,瀏覽器
request模塊同時還有:處理受權驗證(authenticaton)、重定向(redirection)、瀏覽器Cookies以及其餘內容。cookie
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
urlopen參數介紹:網絡
url用於請求URL函數
data不傳:GET請求,傳:POST請求工具
timeout設置超時時間,單位爲秒,意思就是若是請求超出了設置的這個時間,尚未獲得響應,就會拋出異常。若是不指定該參數,就會使用全局默認時間。它支持HTTP、HTTPS、FTP請求。
context必須是ssl.SSLContext類型,用來指定SSL設置。
cafile指定CA證書
capath指定CA證書的路徑,這個在請求HTTPS連接時會有用。
class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
Request參數介紹:
url用於請求URL,這是必傳參數,其餘都是可選參數。
data若是要傳,必須傳bytes(字節流)類型的。若是它是字典,能夠先用urllib.parse模塊裏的urlencode()編碼。
headers是一個字典,它就是請求頭,咱們能夠在構造請求時經過headers參數直接構造,也能夠經過調用請求實例的add_header()方法添加。添加請求頭最經常使用的用法就是經過修改User-Agent來假裝瀏覽器
origin_req_host指的是請求方的host名稱或者IP地址。
unverifiable表示這個請求是不是沒法驗證的,默認是False,意思就是說用戶沒有足夠權限來選擇接收這個請求的結果。例如,咱們請求一個HTML文檔中的圖片,可是咱們沒有自動抓取圖像的權限,這時unverifiable的值就是True`。
method是一個字符串,用來指示請求使用的方法,好比GET、POST和PUT等。
from urllib import request, parse url = 'http://httpbin.org/post' headers = { 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', 'Host': 'httpbin.org' } dict = { 'name': 'Germey' } data = bytes(parse.urlencode(dict), encoding='utf8') req = request.Request(url=url, data=data, headers=headers, method='POST') response = request.urlopen(req) print(response.read().decode('utf-8'))
urllib.request模塊裏的BaseHandler類,它是全部其餘Handler的父類。
常見Handler介紹:
HTTPDefaultErrorHandler:用於處理HTTP響應錯誤,錯誤都會拋出HTTPError類型的異常。
HTTPRedirectHandler:用於處理重定向。
HTTPCookieProcessor:用於處理Cookies。
ProxyHandler:用於設置代理,默認代理爲空。
HTTPPasswordMgr:用於管理密碼,它維護了用戶名和密碼的表。
HTTPBasicAuthHandler:用於管理認證,若是一個連接打開時須要認證,那麼能夠用它來解決認證問題。
ProxyHandler,其參數是一個字典,鍵名是協議類型(好比HTTP或者HTTPS等),鍵值是代理連接,能夠添加多個代理。
而後,利用這個Handler及build_opener()方法構造一個Opener,以後發送請求便可。
from urllib.error import URLError from urllib.request import ProxyHandler, build_opener proxy_handler = ProxyHandler({ 'http': 'http://127.0.0.1:9743', 'https': 'https://127.0.0.1:9743' }) opener = build_opener(proxy_handler) try: response = opener.open('https://www.baidu.com') print(response.read().decode('utf-8')) except URLError as e: print(e.reason)
# 從網頁獲取cookie,並逐行輸出 import http.cookiejar, urllib.request cookie = http.cookiejar.CookieJar() handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') for item in cookie: print(item.name+"="+item.value) # 從網頁獲取cookie,保存爲文件格式 filename = 'cookies.txt' cookie = http.cookiejar.MozillaCookieJar(filename) # cookie = http.cookiejar.LWPCookieJar(filename) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') cookie.save(ignore_discard=True, ignore_expires=True) PS:MozillaCookieJar是CookieJar的子類,LWPCookieJar與MozillaCookieJar都可讀取、保存cookie,但格式不一樣
調用load()方法來讀取本地的Cookies文件,獲取到了Cookies的內容。
cookie = http.cookiejar.LWPCookieJar() cookie.load('cookies.txt', ignore_discard=True, ignore_expires=True) handler = urllib.request.HTTPCookieProcessor(cookie) opener = urllib.request.build_opener(handler) response = opener.open('http://www.baidu.com') print(response.read().decode('utf-8'))
from urllib import request, error try: response = request.urlopen('http://cuiqingcai.com/index.htm') except error.URLError as e: print(e.reason)
urlparse()
urlunparse()
urlsplit()
urlunsplit()
urljoin()
urlencode()
parse_qs()
parse_qsl()
quote()
unquote()
Robots協議也稱做爬蟲協議、機器人協議,它的全名叫做網絡爬蟲排除標準(Robots Exclusion Protocol),用來告訴爬蟲和搜索引擎哪些頁面能夠抓取,哪些不能夠抓取。它一般是一個叫做robots.txt的文本文件,
通常放在網站的根目錄下。www.taobao.com/robots.txt
robotparser模塊提供了一個類RobotFileParser,它能夠根據某網站的robots.txt文件來判斷一個爬取爬蟲是否有權限來爬取這個網頁。
urllib.robotparser.RobotFileParser(url='') # set_url():用來設置robots.txt文件的連接。 # read():讀取robots.txt文件並進行分析。 # parse():用來解析robots.txt文件。 # can_fetch():該方法傳入兩個參數,第一個是User-agent,第二個是要抓取的URL。 # mtime():返回的是上次抓取和分析robots.txt的時間。 # modified():將當前時間設置爲上次抓取和分析robots.txt的時間。
from urllib.robotparser import RobotFileParser rp = RobotFileParser() rp.set_url('http://www.jianshu.com/robots.txt') rp.read() print(rp.can_fetch('*', 'http://www.jianshu.com/p/b67554025d7d')) print(rp.can_fetch('*', "http://www.jianshu.com/search?q=python&page=1&type=collections"))
get()、post()、put()、delete()方法分別用於實現GET、POST、PUT、DELETE請求。
import requests ======================================================== # GET請求 data = { 'name': 'germey', 'age': 22 } r = requests.get("http://httpbin.org/get", params=data) print(r.text) ======================================================== # POST請求 data = {'name': 'germey', 'age': '22'} r = requests.post("http://httpbin.org/post", data=data) print(r.text)
import requests r = requests.get('http://www.jianshu.com') print(type(r.status_code), r.status_code) # status_code屬性獲得狀態碼 print(type(r.headers), r.headers) # 輸出headers屬性獲得響應頭 print(type(r.cookies), r.cookies) # 輸出cookies屬性獲得Cookies print(type(r.url), r.url) # 輸出url屬性獲得URL print(type(r.history), r.history) # 輸出history屬性獲得請求歷史
import requests files = {'file': open('favicon.ico', 'rb')} r = requests.post("http://httpbin.org/post", files=files) print(r.text)
# 獲取Cookies import requests r = requests.get("https://www.baidu.com") print(r.cookies) for key, value in r.cookies.items(): print(key + '=' + value)
import requests s = requests.Session() s.get('http://httpbin.org/cookies/set/number/123456789') r = s.get('http://httpbin.org/cookies') print(r.text)
requests還提供了證書驗證的功能。當發送HTTP請求的時候,它會檢查SSL證書,咱們可使用verify
參數控制是否檢查此證書。其實若是不加verify
參數的話,默認是True
,會自動驗證。
# 經過verity參數設置忽略警告 import requests from requests.packages import urllib3 urllib3.disable_warnings() response = requests.get('https://www.12306.cn', verify=False) print(response.status_code) # 經過捕獲警告到日誌的方式忽略警告 import logging import requests logging.captureWarnings(True) response = requests.get('https://www.12306.cn', verify=False) print(response.status_code) # 指定一個本地證書用做客戶端證書,這能夠是單個文件(包含密鑰和證書)或一個包含兩個文件路徑的元組 import requests response = requests.get('https://www.12306.cn', cert=('/path/server.crt', '/path/key')) print(response.status_code)
import requests proxies = { "http": "http://10.10.1.10:3128", "https": "http://10.10.1.10:1080", } requests.get("https://www.taobao.com", proxies=proxies)
import requests # 超時拋出異常 r = requests.get("https://www.taobao.com", timeout = 1) print(r.status_code) # 請求分爲兩個階段,即鏈接(connect)和讀取(read),能夠分別指定,傳入一個元組 r = requests.get('https://www.taobao.com', timeout=(5,11, 30)) # 永久等待 r = requests.get('https://www.taobao.com', timeout=None) r = requests.get('https://www.taobao.com')
# 使用requests自帶的身份認證功能 import requests from requests.auth import HTTPBasicAuth r = requests.get('http://localhost:5000', auth=HTTPBasicAuth('username', 'password')) print(r.status_code) # 傳一個元組,默認使用HTTPBasicAuth類來認證 import requests r = requests.get('http://localhost:5000', auth=('username', 'password')) print(r.status_code)
模式 | 描述 |
\w | 匹配字母、數字及下劃線 |
\W | 匹配不是字母、數字及下劃線的字符 |
\s | 匹配任意空白字符,等價於[\t\n\r\f] |
\S | 匹配任意非空字符 |
\d | 匹配任意數字,等價於[0-9] |
\D | 匹配任意非數字的字符 |
\A | 匹配字符串開頭 |
\Z | 匹配字符串結尾,若是存在換行,只匹配到換行前的結束字符串 |
\z | 匹配字符串結尾,若是存在換行,同時還會匹配換行符 |
\G | 匹配最後匹配完成的位置 |
\n | 匹配一個換行符 |
\t | 匹配一個製表符 |
^ | 匹配一行字符串的開頭 |
$ | 匹配一行字符串的結尾 |
. | 匹配任意字符,除了換行符,當re.DOTALL標記被指定時,則能夠匹配包括換行符的任意字符 |
[...] | 用來表示一組字符,單獨列出,好比[amk]匹配a、m或k |
[^...] | 不在[]中的字符,好比[^abc]匹配除了a、b、c以外的字符 |
* | 匹配0個或多個表達式 |
+ | 匹配1個或多個表達式 |
? | 匹配0個或1個前面的正則表達式定義的片斷,非貪婪方式 |
{n} | 精確匹配n個前面的表達式 |
{n,m} | 匹配n到m次由前面正則表達式定義的片斷,貪婪方式 |
a|b | 匹配a或b |
( ) | 匹配括號內的表達式,也表示一個組 |
修飾符 | 描述 |
re.I | 使匹配對大小寫不敏感 |
re.L | 作本地化識別(locale-aware)匹配 |
re.M | 多行匹配,影響^和$ |
re.S | 使.匹配包括換行在內的全部字符 |
re.U | 根據Unicode字符集解析字符。這個標誌影響\w、\W、 \b和\B |
re.X | 該標誌經過給予你更靈活的格式以便你將正則表達式寫得更易於理解 |
match()方法會嘗試從字符串的起始位置匹配正則表達式,match()方法中,第一個參數傳入了正則表達式,第二個參數傳入了要匹配的字符串。group()方法能夠輸出匹配到的內容;span()方法能夠輸出匹配的範圍。
search()方法在匹配時會掃描整個字符串,而後返回第一個成功匹配的結果。
findall()方法會搜索整個字符串,而後返回匹配正則表達式的全部內容。
sub()方法可將一串文本中的全部數字都去掉。
compile()方法將正則字符串編譯成正則表達式對象,以便在後面的匹配中複用。
split()方法將字符串用給定的正則表達式匹配的字符串進行分割,分割後返回結果list。
XPath,全稱XML Path Language,即XML路徑語言,它是一門在XML文檔中查找信息的語言。
使用XPath來對網頁進行解析,首先導入lxml庫的etree模塊,而後聲明瞭一段HTML文本,調用HTML類進行初始化,這樣就成功構造了一個XPath解析對象。etree模塊能夠自動修正HTML文本。
html = etree.HTML(text) result = etree.tostring(html) print(result.decode('utf-8')) # 利用XPath規則提取信息 html = etree.parse('./test.html', etree.HTMLParser()) result = html.xpath(’//*’) print(result) # 屬性多值匹配,採用contains()函數 html = etree.HTML(text) result = html. xpath (’//li[contains(@class,」li」)]/a/text()’) print(result) # 多屬性匹配,藉助and運算符實現 html = etree.HTML(text) result = html. xpath(' //li[contains(@class,」li") and @name=item」]/a/text()' ) print(result) # 按序選擇節點,藉助中括號傳入索引的方法獲取特定次序的節點 html = etree.HTML(text) result = html. xpath (’//li[l]/a/text()’) print(result) result = html.xpath(’I /li[last()] /a/text()’) print(result) result = html.xpath(’I !li [position() <3] I a/text()’) print (resl肚) result = html. xpath (’I /li [last ()-2] /a/text()’) print(result) # 節點軸選擇,未完待續
表達式 | 描述 |
nodename | 選取此節點的全部子節點 |
/ | 從當前節點選取直接子節點 |
// | 從當前節點選取子孫節點 |
. | 選取當前節點 |
.. | 選取當前節點的父節點 |
@ | 選取屬性 |
text = ''' <div> <ul> <li class="item-0"><a href="link1.html">first item</a></li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-inactive"><a href="link3.html">third item</a></li> <li class="item-1"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a> </ul> </div> '''
from lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) # 選取全部節點 result = html.xpath('//*') print(result) result = html.xpath('//li') print(result) print(result[0]) # 選取子節點 result = html.xpath('//li/a') print(result) # 選取父節點 result = html.xpath('//a[@href='link4.html']/../@class') print(result)
for lxml import etree
html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li[@class='item-0']') print(result)
for lxml import etree html = etree.parse('./test.html',etree.HTMLParser()) result = html.xpath('//li[@class='item-0']/text()') print(result) # 屬性多值匹配 html = etree.HTML(text) result = html.xpath('//li[contains(@class,'li')]/a/text()') print(result) # 多屬性匹配 html = etree.HTML(text) result = html.xpath('//li[contains(@class,li) and @name='item']/a/text()') print(result)
Beautiful Soup就是Python的一個HTML或XML的解析庫,能夠用它來方便地從網頁中提取數據。Beautiful Soup自動將輸入文檔轉換爲Unicode編碼,輸出文檔轉換爲UTF-8編碼。
html = """ <html><head><title>The Dormouse's story</title></head> <body> <p class="title" name="dromouse"><b>The Dormouse's story</b></p> <p class="story">Once upon a time there were three little sisters; and their names were <a href="http://example.com/elsie" class="sister" id="link1"><!-- Elsie --></a>, <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; and they lived at the bottom of a well.</p> <p class="story">...</p> """
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.title) print(soup.head) print(soup.p) # 若是有多個p標籤,只輸出第一個
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.title.name)
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.p.attrs['name']) print(soup.p['name'])
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.p.contents) # 獲取子節點 print(soup.p.children) # 獲取子節點 for i,child in enumerate(soup.p.children): print(i,child) print(soup.p.descendants) # 獲取子孫節點 for i,child in enumerate(soup.p.descendants): print(i,child)
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.a.parent) # 獲取父節點 print(list(enumerate(soup.a.parents))) # 獲取祖先節點 print(list(enumerate(soup.a.next_siblings))) # 獲取下一兄弟節點 print(list(enumerate(soup.a.previous_siblings))) # 獲取上一個兄弟節點
解析器 | 使用方法 | 優點 | 劣勢 |
Python標準庫 | BeautifulSoup(markup, "html.parser") | Python的內置標準庫、執行速度適中、文檔容錯能力強 | Python 2.7.3及Python 3.2.2以前的版本文檔容錯能力差 |
lxml HTML解析器 | BeautifulSoup(markup, "lxml") | 速度快、文檔容錯能力強 | 須要安裝C語言庫 |
lxml XML解析器 | BeautifulSoup(markup, "xml") | 速度快、惟一支持XML的解析器 | 須要安裝C語言庫 |
html5lib | BeautifulSoup(markup, "html5lib") | 最好的容錯性、以瀏覽器的方式解析文檔、生成HTML5格式的文檔 | 速度慢、不依賴外部擴展 |
find_all()根據標籤名、屬性、內容查找文檔 find_all(narne,attrs,recursive,text,**kwargs) # 標籤名查詢 print(soup.findall(name=’ul')) print(type(soup.find_all(name=’ul’)[0])) # 屬性查詢 print(soup.幹ind_all(attrs={’id':’list-1'})) print(soup.於ind_all(attrs={’name':’elements’})) # 文本查詢 print(soup.find_all(text=re.compile(’link'))) find_all() # 返回全部元素 find() # 返回單個元素 find_parents() # 返回全部祖先節點 find_parent() # 返回直接父節點 find_next_siblings() # 返回後面全部的兄弟節點 find_next_sibling() # 返回後面第一個兄弟節點 find_previous_siblings() # 返回前面全部兄弟節點 find_previous_sibling() # 返回前面第一個兄弟節點 find_all_next() # 返回節點後全部符合條件的節點 find_next() # 返回第一個符合條件的節點 find_all_previous() # 返回節點後全部符合條件的節點 find_previous() # 返回第一個符合條件的節點
經過select()直接傳入CSS選擇器便可完成選擇
html= ''' <div class='panel'> <div class='panel-heading'> <h4>Hello</h4> </div> <div class='panel-body'> <ul class='list' id='list-1'> <li class='element'>Foo</li> <li class='element'>Bar> <li class='element'>Jay</li> </ul> <ul class='list list-small' id='list-2'> <li class='element'>Foo</li> <li class='element'>Bar</li> </ul> </div> </div> '''
from bs4 import BeautifulSoup soup = BeautifulSoup(html, ’lxml' ) print(soup.select('.panel.panel-heading')) print(soup.select('ul li')) print(soup.select('#list-2.element'))
from bs4 import BeautifulSoup soup = BeautifulSoup(html, ’lxml' ) for ul in soup.select('ul'): print(ul['id']) print(ul.attrs['id'])
from bs4 import BeautifulSoup soup = BeautifulSoup(html, ’lxml' ) for ul in soup.select('li'): print(ul.get_text())
html = ''' <div> <ul> <li class="item-0">first item<lli> <li class="item-1"><a href="link2.html">second item</a><lli> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> <li class ="item-1 active"><a href="link4 . html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> '''
# 字符串初始化 from pyquery import PyQuery as pq doc = pd(html) print(doc('li')) # URL初始化 from pyquery import PyQuery as pq doc = pq(url=' https://cuiqingcai.com’) print(doc(’title')) # 文件初始化 from pyquery import PyQuery as pq doc = pq(filename=’demo.html’) print(doc(’li’))
from pyquery import PyQuery as pq doc = pd(html) # 子元素 items = doc('.list') lis = items.find('li') lis = items.children() lis = items.children('.active') print(lis) # 父元素 items = doc('.list') container =items.parents() print(container) parent = items.parents('.wrap') print(parent) # 兄弟元素 li = doc('.list.item-0.active') print(li.siblings()) print(li.siblings('.active'))
from pyquery import PyQuery as pq doc = pd(html) a = doc('.item-0.active a') print(a) print(a.attr.href) print(a.attr('href')
from pyquery import PyQuery as pq doc = pd(html) a = doc('.item-0.active a') print(a) print(a.text())
from pyquery import PyQuery as pq doc = pd(html) li = doc('.item-0.active') print(li) print(li.html())