2021-09-01 学习笔记:Python爬虫、数据可视化
2021-09-01 學習筆記:Python爬蟲、數據可視化
結于2021-09-07;
內容來自 成都工業大學 數字媒體專業實訓;
主要內容:
- PyCharm開發Python腳本的基礎配置;
- Python爬蟲基礎:正則匹配(re)、網頁獲取(urllib)、網頁解析(bs4/BeautifulSoup)
- 數據存儲:數據庫操作(sqlite3/pymysql)、簡單excel編輯(xlwt);
- 數據可視化:Flask:Web框架、 Echarts、 WordCloud
內容很豐富,老師講的很好;
筆記內容僅對個人知識進行補充,詳細課程可以自行學習;
開發環境
Python無法進行代碼加密;
Python安裝及環境變量設置:
- 環境變量:Python目錄 和 該目錄下的Scripts工具目錄;
PyCharm IDE;
- 這里使用anaconda提供的conda環境,管理Pyhton版本,沒有單獨安裝和配置Pyhton,這里新初始化的環境是Python3.9;
- 初始化一個python工程項目;
- IDE右上角,或cmd+,打開設置,Editor->Font,可以設置字體;
- Editor->File and Code Templates,可以設置模塊通用的模板;
- 檢查當前項目的Python解釋器路徑,如果與新建項目時不符,則需要進行解釋器路徑的配置;
- 這里第一張圖,也是當前環境安裝Python擴展庫的地方(還可以指定安裝源),目前顯示了已將安裝的擴展庫;
- 模塊通用的模板示例如下:
- 新建一個腳本,打印一條語句,右鍵選中腳本文件,選擇Run即可運行程序;
- 雙擊文件名進行文件編輯
- 文件名修改方式如下:
Pyhton基礎
- 查看關鍵字:
- 邏輯與或非:and/or/not
- 判斷在不在序列:in/not in
- 判斷是不是類實例:is/is not
- break continue pass
- Python3默認是UTF-8編碼,所有字符串都是unicode字符串;
其他基礎內容參考Learning Python的學習筆記,這里略過;
Python爬蟲基礎
需求:
- 爬取豆瓣電影Top250,信息;
爬蟲基礎知識:
- 根據用戶需求定向,自動抓取互聯網信息的腳本;
百度指數可以對比關鍵字的檢索量,如電影天堂,愛奇藝;電影天堂通過網絡資源引流,廣告變現;天眼查通過整合信息,賣會員變現;
請求網頁:
- cookies:用戶信息
- user-agent:瀏覽器信息
涉及到的庫:
import sys import re # 正則匹配 import urllib.request, urllib.error # 獲取網頁 import sqlite3 # sqlite數據庫操作 import bs4 # 解析網頁 from bs4 import BeautifulSoup # 解析網頁 import xlwt # excel操作Python3 的urllib 整合了urllib2的功能,現在只需要用urllib即可;
測試的網址:
- httpbin.org這是github的一個測試網絡請求和響應的網址;
urllib
import urllib.request import urllib.parse import urllib.errorclass HQUrlLibBlocking:def __init__(self):self.headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'}def getRequestParseHtmlFromUrlSimple(self, url):"""進行get請求,直接打開網頁,獲取網頁信息"""try:response = urllib.request.urlopen(url, timeout=15)print(response.status)html_r = response.read().decode('utf-8')return html_rexcept urllib.error.URLError as e:print(e)def getRequestParseHtmlFromUrl(self, url):"""進行get請求,直接打開網頁,獲取網頁信息"""try:request = urllib.request.Request(url, headers=self.headers, method='GET')response = urllib.request.urlopen(request, timeout=15)print(response.status)html_r = response.read().decode('utf-8')return html_rexcept urllib.error.URLError as e:print(e)def postRequestParseHtmlFromUrlSimple(self, url, params):"""進行post請求,未攜帶header瀏覽器信息,獲取網頁信息"""try:data = bytes(urllib.parse.urlencode(params), encoding='utf-8')response = urllib.request.urlopen(url, data=data, timeout=15)print(response.status)html_r = response.read().decode('utf-8')return html_rexcept urllib.error.URLError as e:print(e)def postRequestParseHtmlFromUrl(self, url, params):"""進行post請求,獲取網頁信息"""try:data = bytes(urllib.parse.urlencode(params), encoding='utf-8')request = urllib.request.Request(url, data=data, headers=self.headers, method='POST')response = urllib.request.urlopen(request, timeout=15)print(response.status)html_r = response.read().decode('utf-8')return html_rexcept urllib.error.URLError as e:print(e)if __name__ == '__main__':content_get = HQUrlLibBlocking().getRequestParseHtmlFromUrl('http://httpbin.org/get')print(content_get)postParams = {'hello':'world'}content_post = HQUrlLibBlocking().postRequestParseHtmlFromUrl('http://httpbin.org/post',postParams)print(content_post)print('over')BeautifulSoup4
with open('./testBS4.html','rb') as file:html = file.read()# 將復雜的HTML文檔轉換成復雜的樹形結構,每個節點都是Python對象bs = BeautifulSoup(html, 'html.parser')print(bs.title)print(bs.li)print(bs.title.string)print(bs.li.attrs)t_list = bs.find_all('li')print(t_list)- 將復雜的HTML文檔轉換成復雜的樹形結構,每個節點都是Python對象,所有對象可以歸納為4種;
- Tag:html文檔標簽對象,默認只拿到第一個;
- NavigableString:Tag包裹的內容.string,Tag的屬性.attrs;
- BeautifulSoup:整個Document文檔對象;
- Comment:注釋,會不包含注釋符號,只顯示其中文字,是一種特殊的NavigableString;
正則表達式
判斷字符串是否符合一定的模式
re模塊:
- re.search():在一個字符串中搜索匹配正則的第一個位置,返回match對象
- re.match():從一個字符串的開始位置匹配正則,返回match對象
- re.findall():搜索字符串,以列表類型返回全部能匹配到的子串
- re.split():將一個字符串按照正則匹配結果進行分割,返回列表
- re.finditer():搜索字符串,返回一個匹配結果的迭代類型,迭代元素是match對象
- re.sub():在一個字符串中替換所有匹配正則的子串,返回替換后的字符串
re模式:
- 標志修飾符控制匹配模式;
- 多個表示按位|來設置,如re.I | re.M;
- re.I:使匹配對大小寫明暗
- re.L:做本地化識別(locale-aware)匹配
- re.M:多行匹配,影響^ $
- re.S:使.匹配包括換行在內的所有字符
- re.U:更具Unicode字符集解析字符,影響\w \W \b \B
- re.X:該標志通過給予更靈活的格式,便于理解正則
正則表達式知識,可參考《正則校驗-我需要的正則表達式知識》
示例程序
findLink = re.compile(r'<a href="(.*?)">') findImgSrc = re.compile(r'<img.*src="(.*?)"', re.S) # ?非貪婪 findTitle = re.compile(r'<span class="title">(.*)</span>') # 貪婪 ...bs = BeautifulSoup(html, "html.parser") # 使用bs縮小范圍到item for item in bs.find_all('div', class_ = 'item'):item = str(item)# 在item的字符串中 通過正則進行匹配link = re.findall(findLink, item)[0]titles = re.findall(findTitle, item)# 其他判斷 或字符串替換處理if len(titles) == 2:c_title = titles[0]o_title = titles[1]數據保存
- excel操作
- 數據庫操作
excel表保存
- 利用Python庫xlwt將數據寫入excel表格;
這個和Pandas對excel的操作比,還是有點low;
sqlite數據庫保存
- 數據類型(支持這五個數據類型相關的親和類型):
- NULL
- INTEGER:帶符號整數,根據值的大小存儲在1 2 3 4 6 8字節中
- REAL:浮點數,存儲為8字節浮點數字
- TEXT:文本字符串,使用數據庫編碼存儲
- BLOB:blob數據,完全根據它的輸入存儲
其他數據庫基本操作參考《SQL-深入淺出》
mysql數據庫操作
from pymysql import *connect = connect(host='127.0.0.1', port=3306, user='usre',password='password',database='hq_test_local',charset='utf-8')cursor = connect.cursor()cursor.execute('SELECT * FROM %s'%(xm_provinces)) results = cursor.fetchall()# 其他操作基本一致 # 這個函數用來判斷表是否存在 def table_exists(self,table_name): sql = "show tables;"self.cur.execute(sql)tables = [self.cur.fetchall()]table_list = re.findall('(\'.*?\')',str(tables))table_list = [re.sub("'",'',each) for each in table_list]if table_name in table_list:return 1 #存在返回1else:return 0 #不存在返回0如果是使用Navicat Premium進行表結構創建,也可以查看具體表結構創建的SQL:
- 選中表,右鍵存儲SQL文件,僅結構;
- 保存的sql文件中就有對應的創建表的SQL語句;
數據可視化
- Flask:Web框架
- Echarts
- WordCloud
Flask
Flask:
- 是用Python基于Werkzeug工具箱編寫的輕量級web開發框架,面向需求簡單的小應用;
- Flask本身相當于一個內核,其他功能基本都需要第三方擴展,如可以用Flask-extension加入ORM、窗體驗證工具、文件上傳、身份驗證等;
- Flask沒有默認使用的數據庫,可以使用MySQL,也可以使用NoSQL;
- WSGI 采用 Werkzeug(路由模塊)
- 模板引擎適應Jinja2;
關于另一個fastAPI,也可以嘗試使用;
快速網站框架:
- 所有Flask程序都必須創建一個程序實例;
- 客戶端要獲取資源時,一般會通過瀏覽器發起HTTP請求;
- Web服務器使用名為WEB服務器網關接口的WSGI(Web Server Gateway Interface)協議,把來自客戶端的請求交給Flask程序實例;
- 一個HTTP請求,對應Server端一個處理邏輯;
- Flask使用Werkzeug來做路由分發(URL請求和視圖函數之間的對應關系);根據每個URL請求,找打具體的視圖函數;
- 在Flask程序中,路由一般是通過程序實例的裝飾器實現;通過調用視圖函數,獲取到數據后,把數據傳入HTML模板文件中,模板引擎負責渲染HTTP響應數據,然后右Flask返回響應數據給瀏覽器,最后瀏覽器顯示;
Django是一個大而全的框架,更適合工程化開發;
Flask擴展包:
- Flask-SQLLalchemy 操作數據庫
- Flask-migrate 管理遷移數據庫
- Flask-Mail 郵件
- Flask-WTF 表單
- Flask-script 插入腳本
- Flask-Login 認證用戶狀態
- Flask-RESTful 開發REST API工具
- Flask-Bootstrap 集成前端框架
- Flask-Moment 本地化日期和時間
pip install flask
from flask import Flaskapp = Flask(__name__)# 裝飾器的作用是將路由映射到視圖函數index @app.route('/') def index():return 'Hello world!'if __name__ == "__main__":# 啟動web服務器app.run()項目目錄:
app.py # hello world static # 網頁靜態資源 templates # html模板flask的 Debug Mode開啟
修改代碼后,刷新界面就可以看到相應的變化;
# 1.修改當前執行項目的configuration,開啟Flask的debug模式# 2.代碼設置 app.run(debug=True)注:第一步如果創建的是Flak項目,才會有,如果是調用Flask庫進行的調試,直接使用代碼設置就可以了;
flask路由參數解析
# 字符串參數 @app.route("/user/<name>") def welcome(name):return name# 數字參數: int float @app.route("/user/<int:id>") def welcome(id):return str(id)注:路由路徑不可以重復;
html模板-Jinja2
pip install jinja2,安裝Flask時應該已經帶了;
from flask import Flask, render_templateapp = Flask(__name__)@app.route("/") def welcome():return render_template('index.html')if __name__ == '__main__':app.run(debug=True)相應的index.html是定義在templates目錄下的html文件;
html的動態渲染
import datetime from flask import Flask, render_templateapp = Flask(__name__)# 三種變量 @app.route("/") def welcome():# 普通變量time = datetime.date.today()# 列表names = ['a', 'b', 'c']# 字典task = {"work":"WK", "time":"30min"}return render_template('index.html', var=time, list=names, task=task)if __name__ == '__main__':app.run(debug=True) <!--解析結構--><div>Today is {{ var }}</div><ul> <!--控制結構-->{% for name in list %}<li>{{ name }}</li>{% endfor %}</ul> <!--使用表格--><table border="1"> <!--items方法 對應的是一個元組列表 -->{% for key, value in task.items() %}<tr><td>{{key}}</td><td>{{value}}</td></tr>{% endfor %}</table>表單提交
from flask import Flask, render_template, request app = Flask(__name__)# 表單提交頁面 @app.route("/test/register") def register():# templates目錄的文件結構return render_template('test/register.html')# 表單提交請求,必須顯式指定接收方式 @app.route("/test/regist", methods=['POST', 'GET']) def regist():# 通過request獲取請求信息request.method # 請求方式request.form # form表單字典# templates目錄的文件結構return render_template('test/regist.html') # 提示:注冊成功或失敗if __name__ == '__main__':app.run(debug=True)動態獲取請求url根路徑:
<!-- <form method="post" action="http://localhost:5000/test/regist">--><!--動態獲取網址根路徑--><form method="post" action="{{ url_for('test/regist') }}"><label>姓名:<input type="text" name="name"></label><label>年齡:<input type="text" name="age"></label><input type="submit" value="Submit"></form>網頁模板
下載靜態網頁模板進行使用:
- 模板之家;
- BOOTSTAPMADE;
- colorlib;
步驟:
- index.html 放入 templates目錄
- assets 文件夾 放入 static目錄,便于CDN服務器分發;
- 在index.html中 修改引入assets資源的路徑;
- 在index.html中的,保留并修改實際使用部分,其余部分刪除即可;
其他:
- 圖標資源,可以在iconfont上進行下載,替換使用;
- 超鏈接的路由跳轉:<a href='/move'></a>
- 路由跳轉的新頁面,為保持風格,可以在原靜態網頁模板的基礎上再行調整;
列表展示
@app.route('/movie') def movie():datalist = []con = sqlite3.connect("movie.db")cur = con.cursor()sql = "select * from movie250"data = cur.execute(sql)for item in data:datalist.append(item)cur.close()con.close()return render_template("movie.html", movies = datalist) <table class="table table-striped"><tr><td>排名</td><td>名稱</td></tr>{% for movie in movies %}<tr><td>{{movie[0]}}</td><td><a href="{{movie[2]}}" target="_blank">{{movie[1]}}</a></td></tr>{% endfor %} </table>拓展:如何支持分頁?
Echarts
圖表展示
- 在assets/js目錄下,導入echarts.min.js,也可以通過npm來安裝;
- 編寫圖表展示的html頁面,并引入js,<script src="static/assets/js/echarts.min.js"></script>;
詳細示例和教程參考官網 文檔-配置項 即可;
圖表代碼可以copy,也可以download完整的圖表html;
@app.route('/score') def score():score = []num = []con = sqlite3.connect("movie.db")cur = con.cursor()sql = "select score, count(score) from movie250 group by score"data = cur.execute(sql)for item in data:score.append(item[0])num.append(item[1])cur.close()con.close()return render_template("scrore.html", score = score, num = num) xAxisdata: {{score|tojson}} seriexdata: {{num}}這里如果 score 是一個字符串數組,為避免從數據庫讀出的字符串包含特殊字符,可以使用tojson進行轉換;
WordCloud應用
詞云:
- 詞頻高的展示文字大一些;
- 文檔中提供了許多示例,可以參考;
- 如果要支持中文,需要安裝pip install jieba進行中文分詞;
這是文檔中的一個常見示例的實現代碼:
import osfrom os import path from wordcloud import WordCloud# get data directory (using getcwd() is needed to support running example in generated IPython notebook) d = path.dirname(__file__) if "__file__" in locals() else os.getcwd()# Read the whole text. text = open(path.join(d, 'constitution.txt')).read()# Generate a word cloud image wordcloud = WordCloud().generate(text)# Display the generated image: # the matplotlib way: import matplotlib.pyplot as plt plt.imshow(wordcloud, interpolation='bilinear') plt.axis("off")# lower max_font_size wordcloud = WordCloud(max_font_size=40).generate(text) plt.figure() plt.imshow(wordcloud, interpolation="bilinear") plt.axis("off") plt.show()# The pil way (if you don't have matplotlib) # image = wordcloud.to_image() # image.show()我們的網站嵌入詞云:
# pip install jieba import jieba # 分詞 # pip install matplotlib from matplotlib import pyplot as plt # 繪圖 保存 # pip install wordcloud from wordcloud import WordCloud # 詞云from PIL import Image # 圖片處理的庫 import numpy as np # 矩陣運算 import sqlite3 # 數據庫# 獲取文本數據 con = sqlite3.connect('movie.db') cur = con.cursor() sql = 'select instruction from movie250' data = cur.execute(sql) text = '' for item in data:text = text + item[0] cur.close() con.close() # 分詞處理 cut = jieba.cut(text) cut_str = ' '.join(cut)# 遮罩生成詞云 img = Image.open(r"./一張白底的形狀圖.png") img_array = np.array(img)wc = WordCloud(background_color='white',mask=img_array,font_path="msyh.ttc" ) wc.generate_from_text(cut_str)# 繪制圖片 fig = plt.figure(1) plt.imshow(wc) plt.axis('off') # 不顯示坐標軸 # plt.show() plt.save('./static/assets/img/wordcloud.png', dpi=500)Wordcloud安裝不成功的處理:
- 從非官網Python擴展包下載wordcloud模塊的whl文件,名如wordcloud-1.6.0-cp37m-win32.whl,注意這里cp后邊是python版本;
- 使用命令pip install wordcloud-1.6.0-cp37m-win32.whl進行安裝;
- 另外,如果用的是conda的環境,注意記得切換;
WordCloud 配置
WordCloud:
- font_path string 字體路徑
- width int 輸出畫布寬,默認400像素
- height int 輸出畫布高,默認200
- prefer_horizontal float 默認0.9 詞語水平方向排版的概率,相當于垂直方向排版概率0.1
- mask nd-array 默認None 繪制詞云使用的二維遮罩,全白的部分不會被繪制;
- scale float 默認1 表示畫布縮放的比例
- min_font_size int 默認4 顯示上最小的字體大小
- max_font_size
- font_step int 默認1 字體步長,大于1時,運算會快些,但誤差也大;
- max_words number 默認200, 要顯示詞的最大個數
- stopwords set of strings 空時使用內置默認的集合,用于設置需要屏蔽的詞;
- background_color 生成圖片的背景顏色
- mode 默認RGB;可以設置為RGBA,若此時background_color非空,則背景透明
- relative_scaling float 默認0.5 表示詞頻與字體大小的關聯性
- color_func 生成新顏色的函數,為空時,使用默認的方法;
- regexp 正則表達式,用于分割輸入的文本
- collocations bool 默認True,表示是否包括兩個詞的搭配
- colormap 默認viridis,給每個單詞隨機分配顏色,若指定color_func,這被忽略;
- fit_words(frequencies) 根據詞頻生成詞云
- generate(text) 根據文本生成詞云
- generate_from_frequencies(frequencies) 根據詞頻生成詞云
- generate_from_text(text) 根據文本生成詞云
- to_array() 轉化為 numpy array
- to_file(filename) 輸出到文件
Over!
總結
以上是生活随笔為你收集整理的2021-09-01 学习笔记:Python爬虫、数据可视化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uni-app(uniCloud)云开发
- 下一篇: 强智02