爬蟲學習
1、 第一隻爬蟲:
import requests
r = requests.get("http://www.baidu.com")
# HTTP請求的返回狀態,200表示連接成功,404表示失敗
print(r.status_code)
# # r的類型,屬於Response
# print(type(r))
#
# # 請求的頭部部分
# print(r.headers)
# HTTP響應內容的字符串形式,即,url對應的頁面內容
# 基本會出現亂碼
print(r.text)
# 從HTTP header中猜測的響應內容的編碼方式
print(r.encoding)
# 從內容中分析出的響應內容編碼方式(備選編碼方式)
print(r.apparent_encoding)
# 解決亂碼問題
r.encoding = "utf-8"
print(r.text)
# HTTP響應內容的二進制形式
print(r.content)
爬蟲基本框架:
import requests
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status() # 如果狀態不是200,引發HTTPEroor異常
r.encoding = r.apparent_encoding
return r.text
except:
return "產生異常"
if __name__ == "__main__": # TODO 有點不懂
url = "http://www.baidu.com"
print(getHTMLText(url))
robots協議:
查看方式:http://*****.com/robots.txt
爬取京東華爲手機信息:
1、簡潔版
import requests
r = requests.get("https://item.jd.com/4203985.html")
# 檢查訪問是否正常
print(r.status_code)
# 由頭部檢查網頁編碼方式
print(r.encoding)
# 提取text裏邊從0到1000的字符信息
print(r.text[:1000])
2、 安全版
import requests
url = "https://item.jd.com/4203985.html"
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000])
except:
print("爬取失敗!")
爬取亞馬遜:(模擬瀏覽器,向網站發起請求)
說明:針對不對爬蟲開放的網站進行爬取
1、 簡潔版:
import requests
"""解決辦法,修改User-Agent爲一個瀏覽器字段
Mozilla/5.0是一個標準瀏覽器字段(被多種瀏覽器採用)
"""
kv = {"user-agent": "Mozilla/5.0"}
url = "https://www.amazon.cn/dp/B01M8L5Z3Y/ref=sr_1_1?s=books&ie=UTF8"\
"&qid=1519982182&sr=1-1&keywords=%E6%9E%81%E7%AE%80"
# headers 方法修改。。。請求信息
r = requests.get(url, headers=kv)
print(r.encoding) # url頭部爲utf-8格式
print(r.status_code)
# 'user-agent': 'Mozilla/5.0' 表明修改成功
print(r.request.headers)
print(r.text[:1000])
2、 安全版
import requests
url = "https://www.amazon.cn/dp/B01M8L5Z3Y/ref=sr_1_1?s=books&ie=UTF8"\
"&qid=1519982182&sr=1-1&keywords=%E6%9E%81%E7%AE%80"
try:
kv = {"user-agent": "Mozilla/5.0"}
r = requests.get(url, headers=kv)
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[:1000])
except:
print("爬取失敗!")
百度360搜索關鍵字提交:
說明:使用360搜索時,把wd修改爲q就行了,其他都一樣
1、 簡潔版
import requests
kv = {"wd": "python"}
r = requests.get("http://baidu.com/s", params=kv)
# 訪問狀態
print(r.status_code)
# 發給百度的url實際上是什麼
print(r.request.url)
2、 安全版
import requests
keyword = "python"
try:
kv = {"wd":keyword}
r = requests.get("http://baidu.com/s", params=kv)
print(r.request.url)
r.raise_for_status()
# 顯示爬取的文本長度
print(len(r.text))
except:
print("爬取失敗!")
爬取國家地理圖片:
1、 簡潔版
import requests
path = "D:/abc.jpg"
url = "http://img0.dili360.com/rw9/ga/M00/02/AB/wKgBzFQ26i2AWujSAA_-xvEYLbU441.jpg"
r = requests.get(url)
print(r.status_code)
# print(r.text)
# 打開一個文件,並把它定義爲一個文件標誌符f
with open(path, "wb") as f:
# r.content表示返回內容的二進制形式,再使用write把他寫出了
f.write(r.content)
f.close()
2、 安全版
import requests
import os # TODO 不會
url = "http://img0.dili360.com/rw9/ga/M00/48/4E/wKgBzFllve2AO9VBAEzNdvr41Hs146.tub.jpg"
# 定義一個根目錄
root = "D://pics//"
# 定義本地路徑的文件名稱,而且與網絡文件名最後一部分相同
path = root +url.split("/")[-1] # TODO 不會
try:
# 如果根目錄不存在,就建立一個這樣的目錄
if not os.path.exists(root):
os.mkdir(root)
# 判斷文件存不存在,如果文件不存在就從網上獲取這樣一個文件
if not os.path.exists(path):
r = requests.get(url)
with open(path, "wb") as f:
f.write(r.content)
f.close()
print("文件保存成功!")
else:
print("文件已經存在!")
except:
print("爬取失敗!")
IP地址歸屬地自動查詢:
1、 簡潔版
import requests
kv = {"user-agent": "Mozilla/5.0"}
url = "http://m.ip138.com/ip.asp?ip="
r = requests.get(url + "202.204.80.112")
r = requests.get(url, headers=kv)
print(r.status_code)
print(r.request.headers)
r.encoding = r.apparent_encoding
print(r.text[-500:])
2、 安全版
import requests
url = "http://m.ip138.com/ip.asp?ip="
try:
r = requests.get(url + "202.204.80.112")
r.raise_for_status()
r.encoding = r.apparent_encoding
print(r.text[-500:])
except:
print("爬取失敗!")
beautifulsoup庫安裝:
import requests
r = requests.get("https://python123.io/ws/demo.html")
print(r.text)
demo = r.text
# 導入beautiful庫
from bs4 import BeautifulSoup
# 對demo進行解析(使用html.parse解釋器進行解析)
soup = BeautifulSoup(demo, "html.parser")
print(soup.prettify())
信息提取:
說明:提取網站源碼中的網址鏈接
# 提取HTML中所有的url鏈接
import requests
from bs4 import BeautifulSoup
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
for link in soup.find_all("a"):
print(link.get("href"))
基於bs4庫的HTML內容查找方法:
import requests
from bs4 import BeautifulSoup
r = requests.get("https://python123.io/ws/demo.html")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
"""BeautifulSoup庫提供了一個方法,如下(查找信息)
<>.find_all(name, attrs, recursive, string, **kwargs)
返回一個列表類型,儲存查找的結果
name:對標籤名稱的檢索字符串
attrs:對標籤屬性值的檢索字符串,可標註屬性檢索
recursive:是否對某一個標籤子孫所有節點進行搜索,默認是True(是一個布爾類型的值)
string:對<>..</>中的字符串區域的檢索字符串
"""
""" name方法 """
# # 查找a 標籤內容
# print(soup.find_all("a"))
# # 查找a b 兩個標籤內容
# print(soup.find_all(["a", "b"]))
#
# # 查看有多少個標籤(tag)
# for tag in soup.find_all(True):
# print(tag.name)
#
# print("")
# """若只顯示以b開頭的標籤(tag),
# 這裏需要正則表達式庫
# """
# # 導入正則表達式庫
# import re
# for tag in soup.find_all(re.compile("b")):
# print(tag.name)
""" attrs 方法 """
# # 輸出一個帶有course屬性值的標籤
# print(soup.find_all("p", "course"))
# print("")
#
# # 查找某個屬性值=**,作爲查找依據(查找必須十分精確,不然返回空列表)
# print(soup.find_all(id="link1"))
# print("")
#
# """針對根據屬性查找必須十分精確,解決措施(導入正則表達式)
# 進行比較模糊的查找
# """
# import re
# print(soup.find_all(id=re.compile("link"))) # 查找內容明顯比上面多
""" recursive方法 """
# print(soup.find_all("a"))
# # 檢查a 標籤下的子節點沒有內容,返回空列表[]
# print(soup.find_all("a", recursive=False))
""" string """
# print(soup) # 查看一下soup完整信息
# print("")
# # 同樣查找依據必須十分精確(輸入的字符串必須精確)
# print(soup.find_all(string="Basic Python"))
# print("")
# # 同樣如果引入正則表達式,就可以進行模糊檢索soup裏的內容
# import re
# print(soup.find_all(string=re.compile("python")))
中國大學排名定向爬蟲:
程序結構設計:
步驟一: 從網絡上獲取大學排名網頁內容
步驟二:提取網頁內容中的有用信息並把他放到合適的數據結構中
步驟三:利用數據結構展示並輸出結果
import requests
from bs4 import BeautifulSoup
import bs4
"""獲取url信息,輸出url內容"""
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
"""將這一個頁面放到ulist中"""
def fillUnivList(ulist, html):
# 解析HTML
soup =BeautifulSoup(html, "html.parser")
# 解析html中tbody所在位置,在tbody標籤中找到每一所大學對應的tr標籤
for tr in soup.find("tbody").children:
# 在tr標籤中找到其中td標籤的信息,並把需要的標籤加到列表中
# isinstance是bs4庫中方法,篩選tr中有標籤的信息(排除沒有標籤的信息)
if isinstance(tr, bs4.element.Tag):
tds = tr("td")
ulist.append([tds[0].string, tds[1].string, tds[2].string])
"""將ulist信息打印出來"""
def printUnivList(ulist, num):
# 打印表頭
print("{:^10}\t{:^6}\t{:^10}".format("排名", "學校名稱", "總分"))
for i in range(num):
u = ulist[i]
print("{:^10}\t{:^6}\t{:^10}".format(u[0], u[1], u[2]))
# 主函數
def main():
uinfo = []
url = "http://zuihaodaxue.cn/shengyuanzhiliangpaiming2018.html"
html =getHTMLText(url)
fillUnivList(uinfo, html)
printUnivList(uinfo, 20) # 獲取20所學校排名
main()
Beautiful Soup庫:
bs類基本元素:
Tag:標籤,基本信息組織單元,分別用<>和</> 標明開頭和結尾
Name:標籤的名字,<>…</p>的名字是’p’ ,格式:<tag>.name
Attributes:標籤屬性,字典形式組織,格式<tag>.attrs
NavigableString: 標籤內非屬性字符串,<>…</>中字符串,格式:<tag>.string
Comment:標籤內部字符串的註釋部分,一種特殊的Comment類型
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
print(r.text)
print("")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
print(soup.title) # 打印title標籤
print("")
# # a 標籤
# tag = soup.a
# print(tag)
# # 獲取a 標籤名字、a父親的名字(p)、a爺爺標籤的名字(body)
# print(soup.a.name)
# print(soup.a.parent.name)
# print(soup.a.parent.parent.name)
# 標籤中非屬性字符串,NavigableString: 標籤內非屬性字符串,<>…</>中字符串,格式:<tag>.string
# comment 註釋
newsoup = BeautifulSoup()
基於bs4庫的HTML內容遍歷方法:
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
# print(r.text)
print("")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
"""標籤樹的下行遍歷:.contents指將標籤所有子節點存入列表
.children指用於循環遍歷兒子節點
.descendants 子孫節點的迭代類型,包含所有子孫節點,用於遍歷
"""
# # .contents用法
#
# # head標籤、以及他的兒子節點
# print(soup.head)
# print("")
# print(soup.head.contents) # 兒子節點
# # 查看body 標籤兒子的信息
# print(soup.body.contents)
# print(len(soup.body.contents)) # 獲取body 標籤兒子的數量(5個)
# print(soup.body.contents[1]) # 獲取body 標籤兒子節點的第二個
# # .children用法
# for child in soup.body.children:
# print(child)
# # .descendants用法
# for child in soup.body.descendants:
# print(child)
"""標籤樹的上行遍歷
.parent 節點的父親標籤
.parents 節點的先輩(包含父親及其以上)標籤的迭代類型,用於循環遍歷先輩節點
"""
# # parent用法
# print(soup.title.parent) # title的父親是head標籤
# print("")
# print(soup.html.parent) #html 標籤是最高級的標籤類型,他的父親就是自己
# print("")
# print(soup.parent) # soup本身就是一種特殊標籤,他的父親是空的
# # 標籤樹的上行遍歷
# for parent in soup.a.parents:
# print(parent)
# else:
# print(parent.name)
"""標籤樹的平行遍歷(只能發生在同一個父親節點下的各節點間)
.next_sibling:返回按照HTML文本順序的下一個平行節點標籤
.previous_sibling:返回。。。上一個。。
.next_siblings:迭代類型,返回按照HTML文本順序的後續所有平行節點標籤
.previous_siblings:迭代類型,。。。前續。。。
"""
# print(soup.a.next_sibling) # 標籤可以是字符串
# print(soup.a.next_sibling.next_sibling) # a的下下個標籤
# print(soup.a.previous_sibling) # a的上一個標籤
# print(soup.a.previous_sibling.previous_sibling) # a的上上一個標籤
# # 標籤樹的遍歷
# for sibling in soup.a.next_siblings: #遍歷後續節點
# print(sibling)
# for sibling in soup.a.previous_siblings: # 遍歷前續節點
# print(sibling)
基於bs4庫的HTML格式化:
from bs4 import BeautifulSoup
import requests
r = requests.get("https://python123.io/ws/demo.html")
# print(r.text)
print("")
demo = r.text
soup = BeautifulSoup(demo, "html.parser")
# soup.prettify() 用於給標籤增加換行符,使輸出內容更清晰(即格式化)
print(soup.prettify())
print("")
print(soup.a.prettify())
HTML:
HTML是www(World Wide Web)的信息組織方式
正則表達式:(regular expression .re)
變化最大的是年齡說明:正則表達式是用來簡潔表達一組字符串的表達式
不把勞動作爲第一生產力優勢:簡潔,可以簡單地表達很大一個字符串的特徵
re庫基本使用:
"""
re庫的函數用法:一次性使用
解釋:pattern:正則表達式的字符串或原生字符串表示
string:待匹配字符串
flags:正則表達式使用時的控制標記
maxsplit:最大分割數,剩餘部分作爲最後一個元素輸出
repl:替換匹配字符串的字符串
count:匹配的最大次數
re.search() 在一個字符串中搜索匹配正則表達式的第一個位置,返回match對象
格式:re.search(pattern,string, flags=0)
re.match() 在一個字符串的開始位置起匹配正則表達式,返回match對象
格式:re.match(pattern,string, flags=0)
re.findall() 搜索字符串,以列表類型返回全部能匹配的子串
格式:re.findall(pattern,string, flags=0)
re.split() 將一個字符串按照正則表達式匹配結果進行分割,返回列表類型
格式:re.findall(pattern,string, maxsplit=0, flags=0)
re.finditer() 搜索字符串,返回匹配結果的迭代類型,每個迭代元素是match對象
re.finditer(pattern, string, flags=0)
re.sub() 在一個字符串中替換所有匹配正則表達式的子串,返回替換後的字符串
re.finditer(pattern, repl, string, count=0, flags=0)
"""
# # search函數
# import re
# match = re.search(r"[1-9]\d{5}", "BLT 100081")
# if match:
# print(match.group(0))
# # match函數
# import re
# match = re.match(r"[1-9]\d{5}", "BLT 100081")
# if match:
# # 匹配結果是空,無法輸出結果
# print(match.group(0))
# print("")
# match = re.match(r"[1-9]\d{5}", "100081 BLT")
# if match:
# # 正常輸出
# print(match.group(0))
# # findall函數
# import re
# ls = re.findall(r"[1-9]\d{5}", "BLT100081 TSU100084")
# # 返回一個列表
# print(ls)
# # split函數
# import re
# # 輸出不匹配的字符串部分
# print(re.split(r"[1-9]\d{5}", "BLT100081 TSU100084"))
# # 只匹配第一個
# print(re.split(r"[1-9]\d{5}", "BLT100081 TSU100084",maxsplit=1))
# # finditer函數
# import re
# for m in re.finditer(r"[1-9]\d{5}", "BLT100081TSU100084"):
# if m:
# print(m.group(0))
# sub函數
import re
print(re.sub(r"[1-9]\d{5}", ":zipcode", "BLT100081 TSU100084"))
"""
re庫的面向對象用法(先編譯):多次使用,方法 regex = re.compile(pattern, flags=0)
regex(正則表達式)
pattern表示正則表達式的字符串或原生字符串,flags表示正則表達式使用時的控制標記
re庫的等價用法:(方法同上)
regex.search():
regex.match():
regex.findall():
regex.split():
regex.finditer():
regex.sub():
"""
淘寶商品價格爬取:
import re
import requests
# 獲得頁面
def getHTMLText(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status() # 如果狀態不是200,引發HTTPEroor異常
r.encoding =r.apparent_encoding
return r.text
except:
return ""
# 解析頁面,獲取商品名稱、價格
def parsePage(ilt, html):
try:
plt = re.findall(r'\"view_price\"\:\"[\d\.]*\"', html) # TODO 爲什麼把高亮的斜槓 \ 去掉,程序還可以運行
tlt = re.findall(r'\"raw_title\"\:\".*?\"', html)
for i in range(len(plt)):
# eval函數可以將獲取的字符串的雙引號或單引號去掉
# spilt函數使用:分割字符串,獲得鍵值對的後半部分
price = eval(plt[i].split(':')[1])
title = eval(tlt[i].split(':')[1])
ilt.append([price, title])
except:
print("")
# 將商品信息輸出在屏幕上
def printGoodList(ilt):
# tplt 是打印模板
tplt = "{:4}\t{:8}\t{:16}"
# 打印表頭
print(tplt.format("序號", "價格", "商品名稱"))
count = 0
for g in ilt:
count = count + 1
print(tplt.format(count, g[0], g[1]))
# 定義主函數,記錄程序運行整個過程
def main():
goods = "墨水"
# 爬取第一頁和第二頁,所以深度設爲2
depth = 2
start_url = "http://s.taobao.com/search?q="+ goods
# 對輸出變量定義一個變量
infoList = []
# 遍歷頁面信息,單獨訪問並處理每個頁面
for i in range(depth):
# 使用try 對過程中發生的錯誤進行異常判斷
try:
url = start_url + "&s="+ str(44*i)
html = getHTMLText(url)
parsePage(infoList, html)
except:
continue
printGoodList(infoList)
main()