正則表達式(re模塊):
數據的分類:
結構化數據
有固定的格式 如HTML、XML、JSON
非結構化數據
圖片、音頻、視頻 這類數據一般存儲爲二進制
正則:
使用流程:
創建編譯對象:p = re.compile("正則表達式")
對字符串匹配:r = p.match("字符串")
獲取匹配結果:print(r.group())
常用方法:
match(str) 字符串開頭的第一個 返回對象
search(str) 從頭開始匹配 只匹配一個 返回對象
group() 從match或search對象中取值
findall() 所有全局匹配 返回一個列表
表達式:
. 匹配任意字符(除了\n)
\d 匹配數字
\s 空白字符
\S 非空字符
[] 匹配括號內所有內容
\w 字母、數字、下劃線
* 前一個出現0次或多次
? 0次或1次
+ 一次或多次
{m} m次
{m, n} m到n次
貪婪匹配:
再整個表達式匹配成功前提下 儘可能多的去匹配*
非貪婪匹配:
再整個表達式匹配成功前提下 儘可能少的去匹配*
示例(貪婪模式和非貪婪模式)
import re
s = """<div><p>年發的斯蒂芬是否</div></p>
<div><p>年發的斯蒂芬是否</div></p>
"""
# 創建編譯對象 貪婪匹配 re.S代表讓.可以匹配\n字符
p = re.compile("<div><p>.*</div></p>", re.S)
# 匹配字符串s
r = p.findall(s)
# 結果爲一個列表內只有與一個元素
print(r)
# 非貪婪匹配 用?儘可能少的去匹配
p = re.compile("<div><p>.*?</div></p>", re.S)
# 匹配字符串s
r = p.findall(s)
# 結果爲一個列表內有多個元素
print(r)
findall()的分組
import re
#解釋 :先按照整體匹配出來,然後再匹配()中的
# 如果有2個或者多個(),則以元組的方式取顯示
s = "A B C D"
p1 = re.compile('\w+\s+\w+')
print(p1.findall(s))
# ['A B','C D']
p2 = re.compile('(\w+)\s+\w+')
# 第1步 :['A B','C D']
# 第2步 :['A','C']
print(p2.findall(s))
p3 = re.compile('(\w+)\s+(\w+)')
# 第1步 :['A B','C D']
# 第2步 :[('A','B'),('C','D')]
print(p3.findall(s))
7、案例1 :內涵段子腦筋急轉彎抓取
# 思路
#
# 網址 :www.neihan8.com
# 步驟:
# 1、找URL規律
# 第1頁:https://www.neihan8.com/njjzw/
# 第2頁:https://www.neihan8.com/njjzw/index_2.html
# 第3頁:https://www.neihan8.com/njjzw/index_3.html
# 用正則匹配出 題目 和 答案
# p = re.compile('<div class="text-.*?title="(.*?)".*?<div class="desc">(.*?)</div>',re.S)
# 寫代碼
# 發請求
# 用正則匹配
# 寫入本地文件
import urllib.request
import re
import random
class NeihanSpider(object):
def __init__(self):
self.baseurl = "http://www.neihan8.com/wenzi/"
self.headers = {"User-Agent": "Mozilla/5.0"}
self.page = 1
# 下載頁面
def load_page(self, url):
# 隨機獲取1個User-Agent
header_list = [{
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"},
{"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"},
{"User-Agent": "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)"}]
headers = random.choice(header_list)
req = urllib.request.Request(url, headers=headers)
res = urllib.request.urlopen(req)
html = res.read().decode("utf-8")
self.parse_page(html)
# 解析頁面
def parse_page(self, html):
p = re.compile(r'''<div class="text-.*?"title="(.*?)">.*?class="desc">(.*?)</div>''')
r_list = p.findall(html)
self.write_page(r_list)
# 保存頁面
def write_page(self, r_list):
for r_tuple in r_list:
for r_str in r_tuple:
with open("急轉彎.txt", "a", encoding="gb18030") as f:
f.write(r_str.strip() + "\n")
# 主函數
def work_on(self):
self.load_page(self.baseurl)
while True:
c = input("是否繼續...(y/n)")
if c.strip().lower() == "y":
self.page += 1
url = self.baseurl + "index_1.html"
self.load_page(url)
else:
break
if __name__ == "__main__":
sipder = NeihanSpider()
sipder.work_on()
貓眼電影top100榜單,存到csv表格文件中
網址:貓眼電影 - 榜單 - top100榜
目標:抓取電影名、主演、上映時間
知識點講解
csv模塊的使用流程
打開csv文件
with open("測試.csv","a") as f:
初始化寫入對象
writer = csv.writer(f)
寫入數據
writer.writerow(列表)
import csv
with open("貓眼.csv", "a") as f:
# 初始化寫入對象
writer = csv.writer(f)
writer.writerow(["霸王別姬", "張國榮"])
writer.writerow(["唐伯虎點秋香", "周星馳"])
準備工作
找URL
第1頁:http://maoyan.com/board/4?offset=0
第2頁:http://maoyan.com/board/4?offset=10
第n頁:
offset = (n-1)*10
正則匹配
<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?releasetime">(.*?)</p>
import random
import re
import urllib.request
import UserAgent
import csv
class MovieRanking(object):
def __init__(self):
self.baseurl = "http://maoyan.com/board/4?offset="
self.headers = random.choice(UserAgent.headers_list)
self.page = 0
def read_page(self, url):
requuest = urllib.request.Request(url, headers=self.headers)
response = urllib.request.urlopen(requuest)
html = response.read().decode("utf-8")
self.parse_page(html)
def parse_page(self, html):
p = re.compile(r'''<p class="name".*?title="(.*?)".*?class="star">(.*?)</p>.*?class="releasetime">(.*?)</p>''', re.S)
movie_list = p.findall(html)
self.write_page(movie_list)
def write_page(self, movie_list):
for movie in movie_list:
movie_list = [movie[0].strip(), movie[1].strip(), movie[2].strip()]
with open("貓眼Top.csv", "a", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(movie_list)
def main_page(self, number):
i = 0
while i < number:
url = self.baseurl + str(self.page)
self.read_page(url)
self.page += 1
i += 1
if __name__ == "__main__":
movie = MovieRanking()
movie.main_page(100)
Fiddler常用菜單
Inspector : 查看抓到的數據包的詳細內容
分爲請求(request)和響應(response)兩部分
常用選項
Headers :顯示客戶端發送到服務器的header,包含客戶端信息、cookie、傳輸狀態
WebForms :顯示請求的POST數據 <body>
Raw :將整個請求顯示爲純文本
請求方式及案例
GET
POST
Cookie模擬登陸
什麼是cookie、session
HTTP是一種無連接協議,客戶端和服務器交互僅僅限於 請求/響應過程,結束後斷開,下一次請求時,服務器會認爲是一個新的客戶端,爲了維護他們之間的連接,讓服務器知道這是前一個用戶發起的請求,必須在一個地方保存客戶端信息。
cookie :通過在客戶端記錄的信息確定用戶身份
session :通過在服務端記錄的信息確定用戶身份
使用cookie模擬登陸人人網
'''cookie模擬登陸人人網.py'''
import urllib.request
# 步驟:
# 通過抓包工具、F12獲取到cookie(先登陸1次網站)
# 正常發請求
# url:http://www.renren.com/967469305/profile
url = "http://www.renren.com/967469305/profile"
headers = {
"Host":"www.renren.com",
"Connection":"keep-alive",
"Upgrade-Insecure-Requests":"1",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Referer":"http://www.renren.com/",
"Accept-Language":"zh-CN,zh;q=0.9",
"Cookie":"anonymid=jnoaljpk7d3nh2; depovince=BJ; _r01_=1; _de=4DBCFCC17D9E50C8C92BCDC45CC5C3B7; ln_uact=13603263409; ln_hurl=http://head.xiaonei.com/photos/0/0/men_main.gif; jebe_key=1b1f4a34-0468-4185-a3b0-6f2c38abc368%7C2012cb2155debcd0710a4bf5a73220e8%7C1540454149943%7C1%7C1540454153787; wp_fold=0; wp=0; jebecookies=2fc339e7-1b51-43ce-bc85-e2dc1f68ee16|||||; JSESSIONID=abcANrnqoMuLshY34pQAw; ick_login=30d0bd58-f6bb-437f-8d0d-6a72ae00e7b7; p=1e1b85cb8dda387a70e400a341c2e9c95; first_login_flag=1; t=4f652cc0a8f3fd50f5c9095c92d4717d5; societyguester=4f652cc0a8f3fd50f5c9095c92d4717d5; id=967469305; xnsid=55bff2d5; loginfrom=syshome"
}
req = urllib.request.Request(url,headers=headers)
res = urllib.request.urlopen(req)
print(res.read().decode("utf-8"))
requests模塊
安裝(用管理員身份去打開Anaconda Prompt)
Anaconda : conda install requests
Windows cmd: python -m pip install requests
## 以管理員身份去執行pip安裝命令
常用方法
get(url,headers=headers) : 發起請求,獲取響應對象
response屬性
response.text :返回字符串類型
response.content : 返回bytes類型
應用場景 :爬取非結構化數據
response.encoding
一般返回 :ISO-8859-1 # latin1
指定編碼:response.encoding = "utf-8"
response.status_code :返回服務器響應碼
response.url :返回數據的URL地址
get()使用場景
沒有查詢參數
res = requests.get(url,headers=headers)
有查詢參數: params={}
注 :params參數必須爲字典,自動進行編碼
見 :09_requests.get.params.py
post() 參數名 :data
data = {}
爬取鏈家二手房
import csv
import re
import requests
class HouseReptile(object):
def __init__(self):
self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60"}
self.base_url = "https://jn.lianjia.com/ershoufang/pg"
self.pg = 0
print("初始化~")
def read_house(self, url):
print("讀取數據")
response = requests.get(url, self.headers)
self.parse_house(response.text)
def parse_house(self, html):
print("開始解析數據")
# 詳情頁 標題 小區名 規格 樓層 發佈時間 總價 單價
mate = re.compile('''<div class="title"><a class="" href="(.*?)".*?data-is_focus="" data-sl="">(.*?)</a>.*?data-el="region">(.*?)</a> (.*?)<.*?</span>(.*?)<.*?starIcon"></span>(.*?)<.*?<span>(\d+)</span>萬.*?<span>(.*?)</span>''', re.S)
house_list = mate.findall(html)
self.write_house(house_list)
def write_house(self, house_list):
for house in house_list:
with open("鏈接二手房.csv", "a", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
house = [
house[0].strip(),
house[1].strip(),
house[2].strip(),
house[3].strip(),
house[4].strip(),
house[5].strip(),
house[6].strip(),
house[7].strip()
]
writer.writerow(house)
def crawl_house(self, number):
if self.pg == 0:
with open("鏈接二手房.csv", "a", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow([
"房屋詳情鏈接",
"標題",
"小區名",
"規格",
"樓層",
"發佈時間",
"總價(萬)",
"單價"
])
for i in range(0, number):
self.pg += 1
url = self.base_url + str(self.pg)
print("開始爬取:", url)
self.read_house(url)
if __name__ == "__main__":
house = HouseReptile()
house.crawl_house(3)