Selenium+Phantomjsjavascript
儘可能不使用 sleep 而使用 WebDriverWaitcss
(1)iphtml
(2)帶寬前端
(3)cpujava
(4)iopython
URL,即統一資源定位符,也就是咱們說的網址,統一資源定位符是對能夠從互聯網上獲得的資源的位置和訪問方法的一種簡潔的表示,是互聯網上標準資源的地址。互聯網上的每一個文件都有一個惟一的 URL,它包含的信息指出文件的位置以及瀏覽器應該怎麼處理它。mysql
Scrapy,Beautiful Soup, urllib,urllib2,requestsreact
scrapy 是一個快速(fast)、高層次(high-level)的基於 python 的 web 爬蟲構架。jquery
用來下載、並解析 web 頁面, 其 parse->yield item->pipeline 流程是全部爬蟲的固有模式。linux
構造形式主要分spider.pypipeline.py item.py decorator.py middlewares.py setting.py。
(1)優勢:scrapy 是異步的
採起可讀性更強的 xpath 代替正則強大的統計和 log 系統,同時在不一樣的 url 上爬行支持 shell 方式,方便獨立調試寫 middleware,方便寫一些統一的過濾器,經過管道的方式存入數據庫
(2)缺點:基於 python 的爬蟲框架,擴展性比較差
基於 twisted 框架,運行中的 exception 是不會幹掉 reactor,而且異步框架出錯後是不會停掉其餘任務的,數據出錯後難以察覺。
(1)scrapy 是封裝起來的框架,他包含了下載器,解析器,日誌及異常處理,基於多線程, twisted 的方式處理,對於固定單個網站的爬取開發,有優點,可是對於多網站爬取 100 個網站,併發及分佈式處理方面,不夠靈活,不便調整與括展。
(2)request 是一個 HTTP 庫, 它只是用來,進行請求,對於 HTTP 請求,他是一個強大的庫,下載,解析所有本身處理,靈活性更高,高併發與分佈式部署也很是靈活,對於功能能夠更好實現.
應用層—http ftp dns nfs
傳輸層—tcp --udp
網絡層—ip icmp igmp
鏈路層—data link
物理層—media
設置 ip 和掩碼
<pre style="-webkit-tap-highlight-color: transparent; box-sizing: border-box; font-family: Consolas, Menlo, Courier, monospace; font-size: 16px; white-space: pre-wrap; position: relative; line-height: 1.5; color: rgb(153, 153, 153); margin: 1em 0px; padding: 12px 10px; background: rgb(244, 245, 246); border: 1px solid rgb(232, 232, 232); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> Ifconfig eth0 192.168.13.225 netmask 255.255.255.0 </pre>
設置網關
route add default gw 192.168.5.1
2MSL 即兩倍的 MSL,TCP 的 TIME_WAIT 狀態也稱爲 2MSL 等待狀態,當 TCP 的一端發起主動關閉,在發出最後一個 ACK 包後,即第 3 次握手完成後發送了第四次握手的 ACK包後就進入了 TIME_WAIT 狀態,必須在此狀態上停留兩倍的 MSL 時間,等待 2MSL 時間主要目的是怕最後一個 ACK 包對方沒收到,那麼對方在超時後將重發第三次握手的 FIN包,主動關閉端接到重發的 FIN 包後能夠再發一個 ACK 應答包。在 TIME_WAIT 狀態時兩端的端口不能使用,要等到 2MSL 時間結束纔可繼續使用。當鏈接處於 2MSL 等待階段時任何遲到的報文段都將被丟棄。不過在實際應用中能夠經過設置 SO_REUSEADDR 選項達到沒必要等待 2MSL 時間結束再使用此端口。
1.socket 建立一個套接字
2.bind 綁定 ip 和 port
3.listen 使套接字變爲能夠被動連接
4.accept 等待客戶端的連接
5.recv/send 接收發送數據
(1)MSL:報文最大生存時間」,他是任何報文在網絡上存在的最長時間,超過這個時間報文將被丟棄。
(2)TTL:TTL 是 time to live 的縮寫,中文能夠譯爲「生存時間」,這個生存時間是由源主機設置初始值但不是存的具體時間,而是存儲了一個 ip 數據報能夠通過的最大路由數,每通過一個處理他的路由器此值就減 1,當此值爲 0 則數據報將被丟棄,同時發送 ICMP 報文通知源主機。RFC 793 中規定 MSL 爲 2 分鐘,實際應用中經常使用的是 30 秒,1 分鐘和 2 分鐘等。TTL 與 MSL 是有關係的但不是簡單的相等的關係,MSL要大於等於 TTL。
(3)RTT: RTT 是客戶到服務器往返所花時間(round-trip time,簡稱 RTT),TCP 含有動態估算 RTT 的算法。TCP 還持續估算一個給定鏈接的 RTT,這是由於 RTT受網絡傳輸擁塞程序的變化而變化。
1.添加代理
2.下降訪問頻率
User-Agent動態 HTML 數據加載驗證碼處理Cookie
HTTPS 和 HTTP 的區別:
(1)https 協議須要到 ca 申請證書,通常免費證書不多,須要交費。
(2)http 是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的 ssl 加密傳輸協議
(3)http 和 https 使用的是徹底不一樣的鏈接方式用的端口也不同,前者是 80,後者是 443。
(4)http 的鏈接很簡單,是無狀態的
(5)HTTPS 協議是由 SSL+HTTP 協議構建的可進行加密傳輸、身份認證的網絡協議 要比http 協議安全
應用場合:
(1)http:適合於對傳輸速度,安全性要求不是很高,且須要快速開發的應用。如 web 應用,小的手機遊戲等等.
(2)https:https 應該用於任何場景!
如何申請,國內和國外有哪些第三方機構提供安全證書認證。
國內:
國外:
區別:
get:
從指定的服務器中獲取數據。
GET 請求可以被緩存
GET 請求會保存在瀏覽器的瀏覽記錄中
以 GET 請求的 URL 可以保存爲瀏覽器書籤
GET 請求有長度限制
GET 請求主要用以獲取數據
post:
POST 請求不能被緩存下來
POST 請求不會保存在瀏覽器瀏覽記錄中
以 POST 請求的 URL 沒法保存爲瀏覽器書籤
POST 請求沒有長度限制
POST 請求會把請求的數據放置在 HTTP 請求包的包體中,POST 的安全性比 GET的高.可能修改變服務器上的資源的請求.
應用場合:
post:
請求的結果有持續性的反作用(數據庫內添加新的數據行)
若使用 GET 方法,則表單上收集的數據可能讓 URL 過長。
要傳送的數據不是採用 7 位的 ASCII 編碼。
get:
請求是爲了查找資源,HTML 表單數據僅用來幫助搜索。
請求結果無持續性的反作用。
收集的數據及 HTML 表單內的輸入字段名稱的總長不超過 1024 個字符
HTTP 請求會有哪些信息發送到後臺服務器。
請求行 (請求方式、資源路徑和 HTTP 協議版本)POST /demo/login HTTP/1.1
請求消息頭
消息正文(也叫實體內容) username=xxxx&password=1234
(1)從 start_urls 裏獲取第一批 url 併發送請求,請求由引擎交給調度器入請求隊列,獲取完畢後,調度器將請求隊列裏的請求交給下載器去獲取請求對應的響應資源,並將響應交給本身編寫的解析方法作提取處理:1. 若是提取出須要的數據,則交給管道文件處理;
(2)若是提取出 url,則繼續執行以前的步驟(發送 url 請求,並由引擎將請求交給調度器入隊列…),直到請求隊列裏沒有請求,程序結束。
①scrapy 是一個 Python 爬蟲框架,爬取效率極高,具備高度定製性,可是不支持分佈式。而 scrapy-redis 一套基於 redis 數據庫、運行在 scrapy 框架之上的組件,可讓scrapy 支持分佈式策略,Slaver 端共享 Master 端 redis 數據庫裏的 item 隊列、請求隊列和請求指紋集合。
②爲何選擇 redis 數據庫,由於 redis 支持主從同步,並且數據都是緩存在內存中的,因此基於 redis 的分佈式爬蟲,對請求和數據的高頻讀取效率很是高
①使用一個具備登陸狀態的 cookie,結合請求報頭一塊兒發送,能夠直接發送 get 請求,訪問登陸後才能訪問的頁面。
②先發送登陸界面的 get 請求,在登陸頁面 HTML 裏獲取登陸須要的數據(若是須要的話),而後結合帳戶密碼,再發送 post 請求,便可登陸成功。而後根據獲取的 cookie信息,繼續訪問以後的頁面。
scrapy 框架的異步機制是基於 twisted 異步網絡框架處理的,在 settings.py 文件裏能夠設置具體的併發量數值(默認是併發量 16)。
①經過headers反爬蟲:解決策略,僞造headers
②基於用戶行爲反爬蟲:動態變化去爬取數據,模擬普通用戶的行爲, 使用IP代理池爬取或者下降抓取頻率,或 經過動態更改代理ip來反爬蟲
③基於動態頁面的反爬蟲:跟蹤服務器發送的ajax請求,模擬ajax請求,selnium
和phtamjs。或 使用selenium + phantomjs 進行抓取抓取動態數據,或者找到動態數據加載的json頁面。
④驗證碼 :使用打碼平臺識別驗證碼
⑤數據加密:對部分數據進行加密的,能夠使用selenium進行截圖,使用python自帶的pytesseract庫進行識別,可是比較慢最直接的方法是找到加密的方法進行逆向推理。
scrapy。
優點:
劣勢:
②總體上來講: 一些結構性很強的, 定製性不高, 不須要太多自定義功能時用pyspider便可, 一些定製性高的,須要自定義一 些 功能時則使用Scrapy。
scrapy 是一個快速(fast)、高層次(high-level)的基於 python 的 web 爬蟲構架,用於抓取web站點並從頁面中提取結構化的數據。scrapy 使用了 Twisted異步網絡庫來處理網絡通信
Scrapy Engine:這是引擎,負責Spiders、ItemPipeline、Downloader、Scheduler中間的通信,信號、數據傳遞等等!(像不像人的身體?)
Scheduler(調度器): 它負責接受引擎發送過來的requests請求,並按照必定的方式進行整理排列,入隊、並等待Scrapy Engine(引擎)來請求時,交給引擎。
Downloader(下載器):負責下載Scrapy Engine(引擎)發送的全部Requests請求,並將其獲取到的Responses交還給Scrapy Engine(引擎),由引擎交給Spiders來處理,
Spiders:它負責處理全部Responses,從中分析提取數據,獲取Item字段須要的數據,並將須要跟進的URL提交給引擎,再次進入Scheduler(調度器),
Item Pipeline:它負責處理Spiders中獲取到的Item,並進行處理,好比去重,持久化存儲(存數據庫,寫入文件,總之就是保存數據用的)
Downloader Middlewares(下載中間件):你能夠看成是一個能夠自定義擴展下載功能的組件
Spider Middlewares(Spider中間件):你能夠理解爲是一個能夠自定擴展和操做引擎和Spiders中間‘通訊‘的功能組件(好比進入Spiders的Responses;和從Spiders出去的Requests)
工做流程:
數據在整個Scrapy的流向:
程序運行的時候,
引擎:Hi!Spider, 你要處理哪個網站?
Spiders:我要處理23wx.com
引擎:你把第一個須要的處理的URL給我吧。
Spiders:給你第一個URL是XXXXXXX.com
引擎:Hi!調度器,我這有request你幫我排序入隊一下。
調度器:好的,正在處理你等一下。
引擎:Hi!調度器,把你處理好的request給我,
調度器:給你,這是我處理好的request
引擎:Hi!下載器,你按照下載中間件的設置幫我下載一下這個request
下載器:好的!給你,這是下載好的東西。(若是失敗:很差意思,這個request下載失敗,而後引擎告訴調度器,這個request下載失敗了,你記錄一下,咱們待會兒再下載。)
引擎:Hi!Spiders,這是下載好的東西,而且已經按照Spider中間件處理過了,你處理一下(注意!這兒responses默認是交給def parse這個函數處理的)
Spiders:(處理完畢數據以後對於須要跟進的URL),Hi!引擎,這是我須要跟進的URL,將它的responses交給函數 def xxxx(self, responses)處理。還有這是我獲取到的Item。
引擎:Hi !Item Pipeline 我這兒有個item你幫我處理一下!調度器!這是我須要的URL你幫我處理下。而後從第四步開始循環,直到獲取到你須要的信息,
注意!只有當調度器中不存在任何request了,整個程序纔會中止,(也就是說,對於下載失敗的URL,Scrapy會從新下載。)
以上就是Scrapy整個流程了。
官方語言版本:
流程
1.引擎打開一個域名,蜘蛛處理這個域名,並讓蜘蛛獲取第一個爬取的URL。
2.引擎從蜘蛛那獲取第一個須要爬取的URL,而後做爲請求在調度中進行調度。
3.引擎從調度那獲取接下來進行爬取的頁面。
4.調度將下一個爬取的URL返回給引擎,引擎將他們經過下載中間件發送到下載器。
5.當網頁被下載器下載完成之後,響應內容經過下載中間件被髮送到引擎。
6.引擎收到下載器的響應並將它經過蜘蛛中間件發送到蜘蛛進行處理。
7.蜘蛛處理響應並返回爬取到的項目,而後給引擎發送新的請求。
8.引擎將抓取到的項目發送給項目管道,並向調度發送請求。
系統重複第二步後面的操做,直到調度中沒有請求,而後斷開引擎與域之間的聯繫
須要將dont_filter設置爲False開啓去重,默認是False;
對於每個url的請求,調度器都會根據請求的相關信息加密獲得一個指紋信息,而且將指紋信息和set()集合中的指紋信息進行比對,若是set()集合中已經存在這個數據,就不在將這個Request放入隊列中。若是set()集合中沒有,就將這個Request對象放入隊列中,等待被調度。
scrapy的中間件理論上有三種:
Scheduler Middleware,Spider Middleware,Downloader Middleware,
在應用上通常有如下兩種:
1.爬蟲中間件Spider Middleware
主要功能是在爬蟲運行過程當中進行一些處理.
2.下載器中間件Downloader Middleware
主要功能在請求到網頁後,頁面被下載時進行一些處理.
使用
1.Spider Middleware有如下幾個函數被管理:
process_spider_input 接收一個response對象並處理,
位置是Downloader–>process_spider_input–>Spiders(Downloader和Spiders是scrapy官方結構圖中的組件)
process_spider_exception spider出現的異常時被調用
process_spider_output 當Spider處理response返回result時,該方法被調用
process_start_requests 當spider發出請求時,被調用
位置是Spiders–>process_start_requests–>Scrapy Engine(Scrapy Engine是scrapy官方結構圖中的組件)
2.Downloader Middleware有如下幾個函數被管理
- process_request request經過下載中間件時,該方法被調
- process_response 下載結果通過中間件時被此方法處理
- process_exception 下載過程當中出現異常時被調用
1.爬蟲中間件Spider Middleware:主要功能是在爬蟲運行過程當中進行一些處理.爬蟲發起請求request的時候調用,列如更換修改代理ip,修改UA,
2.下載器中間件Downloader Middleware:主要功能在請求到網頁後,頁面被下載時進行一些處理.瀏覽器返回響應response的時候調用,無效的數據,特殊狀況進行重試
一些網站會有相應的反爬蟲措施,例如不少網站會檢測某一段時間某個IP的訪問次數,若是訪問頻率太快以致於看起來不像正常訪客,它可能就會會禁止這個IP的訪問。因此咱們須要設置一些代理服務器,每隔一段時間換一個代理,就算IP被禁止,依然能夠換個IP繼續爬取。
通常urllib使用代理ip的步驟以下:
④ 安裝Opener
from urllib import request,error#構建兩個代理Handler,一個有IP,一個沒有IPproxy = {'http':'206.125.41.135:80'} httpproxy_handler = request.ProxyHandler(proxy) nullproxy_handler = request.ProxyHandler()#定義一個代理開關proxySwitch = False#經過reqest.build_opener()放法使用這些代理Handler對象,建立自定義opener對象 #根據代理開關是否打開,使用不一樣的代理模式if proxySwitch: opener = request.build_opener(httpproxy_handler)else: opener = request.build_opener(nullproxy_handler) url = "http://www.baidu.com"#安裝opnerrequest.install_opener(opener) rsp = request.urlopen(url)print(rsp.status)
2,使用requets代理
import requests# 根據協議類型,選擇不一樣的代理proxies = { "http": "http://12.34.56.79:9527", "https": "http://12.34.56.79:9527"} response = requests.get("http://www.baiodu.com",proxies=proxies)print(response.status_code)
事先用檢測代碼檢測可用的代理,每隔一段時間更換一次代理,若是出現302等狀態碼,
則當即更換下一個可用的IP。
from urllib import requestdef ProxySpider(url,proxy_ip,headers): #將代理IP及其協議載入ProxyHandler賦給一個opener_support變量 opener_support = request.ProxyHandler({"http":proxy_ip}) #將opener_support載入build_opener方法,建立opener opener = request.build_opener(opener_support) request.install_opener(opener) req=request.Request(url,headers=headers) rsp = request.urlopen(req).read() return rsp
設置setting.py中的DOWNLOAD_DELAY,下降爬取速度;
用xpath獲取驗證碼關鍵字,當出現驗證碼時,識別驗證碼後再繼續運行。
對接打碼平臺
雲打碼平臺使用:
在官網中進行普通用戶和開發者用戶註冊
登陸開發者用戶:
a) 示例代碼下載:開發文檔 --> 調用示例及最新DLL --> PythonHTTP示例下載
b) 建立一個軟件:個人軟件 --> 添加新的軟件(後期會使用該軟件的祕鑰和id)
使用示例代碼中的示例代碼對保存本地的驗證碼進行識別
1. 加載瀏覽器driver; 獲取登陸頁面; 使用css選擇器或者xpath找到帳號和密碼輸入框,
併發送帳號和密碼;
2. 若是出現驗證碼則須要先識別驗證碼,在模擬輸入驗證碼或者模擬鼠標拖動;
3. 使用css選擇器或者xpath找到登陸按鈕,使用click模擬點擊;
1. 採用selenium自動登陸獲取cookie,保存到文件;
2. 讀取cookie,比較cookie的有效期,若過時則再次執行步驟1;
3. 在請求其餘網頁時,填入cookie,實現登陸狀態的保持;
加密的三種狀況:
1. 加密+訪問次數限制+每一個頁面相關信息的條目須要點詳情進行二次請求;
2. 複雜的加密算法進行參數+時間戳+sig值,後臺進行 參數+時間限制;
3. 定時同步cookie+每一個界面一個cookie。
破解方法:
1. 使用selenium模擬點擊獲取詳情頁面;
2. 獲取其相應的api接口,GET接口URL,獲取它的json表格內容;
3. 反向分析網頁JS加載內容;
須要計算的數據量大,任務多,一臺機器搞不定或者效率極低,須要多臺機器共同協做(而不是孤立地各作各的,因此須要通訊),最後全部機器完成的任務彙總在一塊兒,完成大量任務.
將一個項目拷貝到多臺電腦上,同時爬取數據
分佈式爬蟲則是將多臺主機組合起來,共同完成一個爬取任務,這將大大提升爬取的效率。
記住爬蟲的本質是網絡請求和數據處理,如何穩定地訪問網頁拿到數據,如何精準地提取出高質量的數據纔是核心問題
①分佈式爬蟲主要由主機與從機組成,咱們把本身的核心服務器(主機)稱爲 master,而把用於跑爬蟲程序的機器(從機)稱爲 slave。
②咱們首先給爬蟲一些start_urls,spider 最早訪問 start_urls 裏面的 url,再根據咱們的 parse 函數,對裏面的元素、或者是其餘的二級、三級頁面進行抓取。而要實現分佈式,只須要在這個starts_urls裏面作文章就好了。進一步描述以下:
②slave 從 master 的 redis 中取出待抓取的 request,下載完網頁以後就把網頁的內容發送回 master 的redis,key 是 spider:items。scrapy 能夠經過 settings 來讓 spider爬取結束以後不自動關閉,而是不斷的去詢問隊列裏有沒有新的 url,若是有新的 url,那麼繼續獲取 url並進行爬取,因此這一過程將不斷循環。
master 裏的 reids 還有一個 key 是 「spider:dupefilter」 用來存儲抓取過的 url 的fingerprint(使用哈希函數將url運算後的結果),防止重複抓取,只要 redis 不清空,就能夠進行斷點續爬。
scrapy實現分佈式抓取簡單點來講能夠藉助scrapy_redis類庫來實現。
在分佈式爬取時,會有master機器和slave機器,其中,master爲核心服務器,slave爲具體的爬蟲服務器。
咱們在master服務器上搭建一個redis數據庫,並將要抓取的url存放到redis數據庫中,全部的slave爬蟲服務器在抓取的時候從redis數據庫中去連接,因爲scrapy_redis自身的隊列機制,slave獲取的url不會相互衝突,而後抓取的結果最後都存儲到數據庫中。master的redis數據庫中還會將抓取過的url的指紋存儲起來,用來去重。相關代碼在dupefilter.py文件中的request_seen()方法中能夠找到。
經過重寫scheduler和spider類,實現了調度、spider啓動和redis的交互。實現新的dupefilter和queue類,達到了判重和調度容器和redis的交互,由於每一個主機上的爬蟲進程都訪問同一個redis數據庫,因此調度和判重都統一進行統一管理,達到了分佈式爬蟲的目的。
1 spider.getStatus();//獲取爬蟲狀態
2 spider.getStatus().equals(Spider.Status.Init);//運行中
分佈式去重問題:
Duplication Filter:
Scrapy中用集合實現這個request去重功能,Scrapy中把已經發送的request指紋放入到一個集合中,把下一個request的指紋拿到集合中比對,若是該指紋存在於集合中,說明這個request發送過了,若是沒有則繼續操做。這個核心的判重功能是這樣實現的:
在scrapy-redis中去重是由Duplication Filter組件來實現的,它經過redis的set 不重複的特性,巧妙的實現了Duplication Filter去重。scrapy-redis調度器從引擎接受request,將request的指紋存⼊redis的set檢查是否重複,並將不重複的request push寫⼊redis的 request queue。
引擎請求request(Spider發出的)時,調度器從redis的request queue隊列⾥里根據優先級pop 出⼀個request 返回給引擎,引擎將此request發給spider處理。
一、最後總結一下scrapy-redis的整體思路:這套組件經過重寫scheduler和spider類,實現了調度、spider啓動和redis的交互。
二、實現新的dupefilter和queue類,達到了判重和調度容器和redis 的交互,由於每一個主機上的爬蟲進程都訪問同一個redis數據庫, 因此調度和判重都統一進行統一管理,達到了分佈式爬蟲的目的。
三、當spider被初始化時,同時會初始化一個對應的scheduler對象, 這個調度器對象經過讀取settings,配置好本身的調度容器queue 和判重工具dupefilter。
四、每當一個spider產出一個request的時候,scrapy引擎會把這個 reuqest遞交給這個spider對應的scheduler對象進行調度, scheduler對象經過訪問redis對request進行判重,若是不重複就 把他添加進redis中的調度器隊列裏。當調度條件知足時,scheduler 對象就從redis的調度器隊列中取出一個request發送給spider, 讓他爬取。
五、當spider爬取的全部暫時可用url以後,scheduler發現這個spider 對應的redis的調度器隊列空了,因而觸發信號spider_idle, spider收到這個信號以後,直接鏈接redis讀取start_urls池,拿 去新的一批url入口,而後再次重複上邊的工做。
詳情請點擊:https://blog.csdn.net/hzp666/article/details/79168675
Redis基於內存,讀寫速度快,也可作持久化,可是內存空間有限,當數據量超過內存空間時,需擴充內存,但內存價格貴;
MySQL基於磁盤,讀寫速度沒有Redis快,可是不受空間容量限制,性價比高;
大多數的應用場景是MySQL(主)+Redis(輔),MySQL作爲主存儲,Redis用於緩存,加快訪問速度。須要高性能的地方使用Redis,不須要高性能的地方使用MySQL。存儲數據在MySQL和Redis之間作同步;
MongoDB 與 MySQL 的適用場景:
MongoDB 的適用場景爲:數據不是特別重要(例如通知,推送這些),數據表結構變化較爲頻繁,數據量特別大,數據的併發性特別高,數據結構比較特別(例如地圖的位置座標),這些狀況下用 MongoDB , 其餘狀況就仍是用 MySQL ,這樣組合使用就能夠達到最大的效率。
今天咱們能夠經過第三方平臺(如:Google,Facebook等)能夠很容易的訪問和抓取數據。用戶的我的信息,社交網絡,地理位置,用戶生成的數據和用戶操做日誌已經成倍的增長。咱們若是要對這些用戶數據進行挖掘,那SQL數據庫已經不適合這些應用了, NoSQL數據庫的發展也卻能很好的處理這些大的數據。
MongoDB
MongoDB 是一個介於關係數據庫和非關係數據庫之間的產品,是非關係數據庫當中功能最豐富,最像關係數據庫的。
它是一個內存數據庫,數據都是放在內存裏面的。
對數據的操做大部分都在內存中,但 MongoDB 並非單純的內存數據庫。
MongoDB 是由 C++ 語言編寫的,是一個基於分佈式文件存儲的開源數據庫系統。
在高負載的狀況下,添加更多的節點,能夠保證服務器性能。
MongoDB 旨在爲 WEB 應用提供可擴展的高性能數據存儲解決方案。
MongoDB 將數據存儲爲一個文檔,數據結構由鍵值(key=>value)對組成。MongoDB 文檔相似於 JSON 對象。字段值能夠包含其餘文檔,數組及文檔數組。
優勢:
1.性能優越:快速!在適量級的內存的 MongoDB 的性能是很是迅速的,它將熱數據存儲在物理內存中,使得熱數據的讀寫變得十分快,
2.高擴展:第三方支持豐富(這是與其餘的 No SQL 相比,MongoDB 也具備的優點)
3.自身的 Failover 機制!
4.弱一致性(最終一致),更能保證用戶的訪問速度
5.文檔結構的存儲方式,可以更便捷的獲取數據: json 的存儲格式
6.支持大容量的存儲,內置 GridFS
7.內置 Sharding
8.MongoDB支持各類編程語言:RUBY,PYTHON,JAVA,C++,PHP,C#等多種語言。
MongoDB 缺點:
主要是無事物機制!
① MongoDB 不支持事務操做(最主要的缺點)
② MongoDB 佔用空間過大
③ MongoDB 沒有如 MySQL 那樣成熟的維護工具,這對於開發和IT運營都是個值得注意的地方
redis
Redis 一個內存數據庫,經過 Key-Value 鍵值對的的方式存儲數據。因爲 Redis 的數據都存儲在內存中,因此訪問速度很是快,所以 Redis 大量用於緩存系統,存儲熱點數據,能夠極大的提升網站的響應速度。
一、Redis優勢
(1)支持數據的持久化,經過配置能夠將內存中的數據保存在磁盤中,Redis 重啓之後再將數據加載到內存中;
(2)支持列表,哈希,有序集合等數據結構,極大的擴展了 Redis 用途;
(3)原子操做,Redis 的全部操做都是原子性的,這使得基於 Redis 實現分佈式鎖很是簡單;
(4)支持發佈/訂閱功能,數據過時功能;
Redis的數據類型
Redis一般被稱爲數據結構服務器,由於值(value)能夠是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等類型。
mysql
MySQL是關係型數據庫。
MySQL是一種關係數據庫管理系統,關係數據庫將數據保存在不一樣的表中,而不是將全部數據放在一個大倉庫內,這樣就增長了速度並提升了靈活性。
MySQL所使用的 SQL 語言是用於訪問數據庫的最經常使用標準化語言。MySQL 軟件採用了雙受權政策,分爲社區版和商業版,因爲其體積小、速度快、整體擁有成本低,尤爲是開放源碼這一特色,通常中小型網站的開發都選擇 MySQL 做爲網站數據庫。
系統特性
1. [2] 使用 C和 C++編寫,並使用了多種編譯器進行測試,保證了源代碼的可移植性。
2.支持 AIX、FreeBSD、HP-UX、Linux、Mac OS、NovellNetware、OpenBSD、OS/2 Wrap、Solaris、Windows等多種操做系統。
3.爲多種編程語言提供了 API。這些編程語言包括 C、C++、Python、Java、Perl、PHP、Eiffel、Ruby,.NET和 Tcl 等。
4.支持多線程,充分利用 CPU 資源。
5.優化的 SQL查詢算法,有效地提升查詢速度。
6.既可以做爲一個單獨的應用程序應用在客戶端服務器網絡環境中,也可以做爲一個庫而嵌入到其餘的軟件中。
7.提供多語言支持,常見的編碼如中文的 GB 23十二、BIG5,日文的 Shift_JIS等均可以用做數據表名和數據列名。
8.提供 TCP/IP、ODBC 和 JDBC等多種數據庫鏈接途徑。
9.提供用於管理、檢查、優化數據庫操做的管理工具。
10.支持大型的數據庫。能夠處理擁有上千萬條記錄的大型數據庫。
11.支持多種存儲引擎。
12.MySQL 是開源的,因此你不須要支付額外的費用。
13.MySQL 使用標準的 SQL數據語言形式。
14.MySQL 對 PHP 有很好的支持,PHP是比較流行的 Web 開發語言。
15.MySQL是能夠定製的,採用了 GPL協議,你能夠修改源碼來開發本身的 MySQL 系統。
16.在線 DDL/更改功能,數據架構支持動態應用程序和開發人員靈活性(5.6新增)
17.複製全局事務標識,可支持自我修復式集羣(5.6新增)
18.複製無崩潰從機,可提升可用性(5.6新增)
19.複製多線程從機,可提升性能(5.6新增)
20.3倍更快的性能(5.7 [3] 新增)
21.新的優化器(5.7新增)
22.原生JSON支持(5.7新增)
23.多源複製(5.7新增)
24.GIS的空間擴展 [4] (5.7新增)
優點:
在不一樣的引擎上有不一樣 的存儲方式。
查詢語句是使用傳統的sql語句,擁有較爲成熟的體系,成熟度很高。
開源數據庫的份額在不斷增長,mysql的份額頁在持續增加。
缺點:
在海量數據處理的時候效率會顯著變慢。
4.是否支持事務…
mongo不支持
redis mysql支持
區別:字符串類型、默認字符、print方法、除法的數字類型、導入方式、繼承類、元類聲明、異常處理、字典、模塊合併、部分模塊重命名(詳情)
代碼遷移:python3有個內部工具叫作2to3.py,位置在Python3/tool/script文件夾。
首先CD到這個文件夾,而後調用
py 2to3.py -w f:/xxxx/xxx.py
具體方法:https://blog.csdn.net/xutiantian1412/article/details/79523953
在python2中主要有str和unicode兩種字符串類型,而到python3中改成了bytes和str,而且一個很重要的分別是,在python2中若是字符串是ascii碼的話,str和unicode是能夠直接進行鏈接和比較,可是到python3中就不行了,bytes和str是兩個獨立的類型。另外一個重要的是python2中無論是str仍是unicode均可以直接寫入文件,而不須要加上它是否是str的類型寫入方式,可是在python3中若是是寫或者讀bytes類型就必需帶上’b’.
生成器:
建立python迭代器的過程雖然強大,可是不少時候使用不方便。生成器是一個簡單的方式來完成迭代。簡單來講,Python的生成器是一個返回能夠迭代對象的函數。
爲何使用生成器
更容易使用,代碼量較小,內存使用更加高效。好比列表是在創建的時候就分配全部的內存空間,而生成器僅僅是須要的時候才使用,更像一個記錄表明了一個無限的流。若是咱們要讀取並使用的內容遠遠超過內存,可是須要對全部的流中的內容進行處理,那麼生成器是一個很好的選擇,好比可讓生成器返回當前的處理狀態,因爲它能夠保存狀態,那麼下一次直接處理便可。
流水線生成器
最簡單的生成器:
g = (x*x for x in range(10))for i in g: print(i)
函數方法實現稍複雜的生成器:
def fib(max): n,a,b=0,1,1 while n<max: yield b a,b=b,a+b n +=1for n in fib(6): print(n)
迭代器概述
能夠直接做用於for循環的數據類型有如下幾種:
一類是集合數據類型,如list,tuple,dict,set,str等
一類是generator ,包括生成器和帶yeild的generator function
這些能夠 直接做用於for循環的對象統稱爲可迭代對象:Iterable
能夠被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator
def hs(n): i=0 while i<n: yield i i+=1a=(hs(1000))print(next(a))print(next(a))print(next(a))print(next(a))print(next(a))
裝飾器:
基本概念:在函數調用先後自動打印日誌,又不改變原函數,在代碼運行期間動態增長功能的方式稱之爲「裝飾器」。
裝飾器的語法以@開頭,接下來是裝飾器函數的名字和可選的參數,緊跟着裝飾器聲明的是被修飾的函數和裝飾函數的可選參數。
**3大特徵:**1,外部函數包含內部函數,2,返回一個內部函數,3,內部函數用到外部函數的變量
import timedef hs(f):#裝飾器的函數,f接受被裝飾的函數名 def neibu():#裝飾內部函數 start=time.time() f()#調用被裝飾的函數 end=time.time() print(end-start) return neibu#裝飾器返回內部函數,(內部表明的是包裝盒)@hs#@加函數名,表明下面的函數被hs裝飾def jisuan(): print('123456') jisuan()
Number(數字) 包括int,long,float,complex
String(字符串) 例如:hello,「hello」,hello
List(列表) 例如:[1,2,3],[1,2,3,[1,2,3],4]
Dictionary(字典) 例如:{1:「nihao」,2:「hello」}
Tuple(元組) 例如:(1,2,3,abc)
Bool(布爾) 包括True、False
Robots協議(也稱爲爬蟲協議、機器人協議等)的全稱是「網絡爬蟲排除標準」(Robots Exclusion Protocol),網站經過Robots協議告訴搜索引擎哪些頁面能夠抓取,哪些頁面不能抓取。
1.http協議,請求由什麼組成,每一個字段分別有什麼用,https和http有什麼差距
請求行(request line)、請求頭部(header)、空行和請求數據四個部分組成(詳情);
④請求數據也叫主體,能夠添加任意的其餘數據;
HTTP協議傳輸的數據都是未加密的,也就是明文的,所以使用HTTP協議傳輸隱私信息很是不安全,爲了保證這些隱私數據能加密傳輸,因而網景公司設計了SSL(Secure Sockets Layer)協議用於對HTTP協議傳輸的數據進行加密,從而就誕生了HTTPS。簡單來講,HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全。
HTTPS和HTTP的區別主要以下:
④ http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
https://blog.csdn.net/fangqun663775/article/details/55189107
https://blog.csdn.net/xiaobangkuaipao/article/details/76793702
JSON文件
JSON Path
轉化爲Python類型進行操做(json類)
XML文件
轉化爲Python類型(xmltodict)
XPath
CSS選擇器
正則表達式
詳情:https://www.cnblogs.com/miqi1992/p/7967399.html
http://tool.oschina.net/uploads/apidocs/jquery/regexp.html
文本、電話號碼、郵箱地址
"^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}KaTeX parse error: Can't use function '\.' in math mode at position 34: …[a-zA-Z0-9_-]+(\̲.̲[a-zA-Z0-9_-]+)…
元字符 含義
. 匹配除換行符之外的任意一個字符
^ 匹配行首
$ 匹配行尾
? 重複匹配0次或1 * 重複匹配0次或更屢次 + 重複匹配1次或更屢次
{n,} 重複n次或更屢次
{n,m} 重複n~m次
[a-z] 任意字符
[abc] a/b/c中的任意一個字符
{n} 重複n次
\b 匹配單詞的開始和結束
\d 匹配數字
\w 匹配字母,數字,下劃線
\s 匹配任意空白,包括空格,製表符(Tab),換行符
\W 匹配任意不是字母,數字,下劃線的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非數字的字符
\B 匹配不是單詞開始和結束的位置
[^a] 匹配除了a之外的任意字符
[^(123|abc)] 匹配除了123或者abc這幾個字符之外的任意字符
爬取動態頁面目前來講有兩種方法
分析很簡單,咱們只須要打開了瀏覽器F12開發者模式,獲取它的js請求文件(除JS選項卡還有可能在XHR選項卡中,固然 也能夠經過其它抓包工具)
咱們打開第一財經網看看,發現沒法獲取元素的內容
打開Network,看下它的請求,這裏咱們只看它的 j s 請求就夠了, 找到json接口
將它的url放到瀏覽器看下,發現是咱們要的數據,就能夠獲取了
一些網站全部的接口都進行了加密操做,咱們沒法解析js,就必須採用selenium+phantomjs進行獲取
採用正則表達式解析:獲取整個json數據後,採用正則表達式匹配到關鍵詞;
使用eval解析
json.loads() 是把Json格式字符串解碼轉換成Python對象,若是在json.loads的時候出錯,要注意被解碼的Json字符的編碼,json.dumps() 是把json_obj 轉換爲json_str
①GET數據傳輸安全性低,POST傳輸數據安全性高,由於參數不會被保存在瀏覽器歷史或web服務器日誌中;
②在作數據查詢時,建議用GET方式;而在作數據添加、修改或刪除時,建議用POST方式;
④GET傳輸數據的數據量較小,只能在請求頭中發送數據,而POST傳輸數據信息比較大,通常不受限制;
⑤在執行效率來講,GET比POST好
賦值:把等號右邊的數據,存儲到左邊變量所開闢的內存空間中
淺拷貝:只拷貝引用不拷貝對象自己,一旦有一個引用修改,全部的引用都會被迫修改
深拷貝:直接拷貝對象自己,產生一個新的對象,而且產生一個新的引用;就是在內存中從新開闢一塊空間,無論數據結構多麼複雜,只要遇到可能發生改變的數據類型,就從新開闢一塊內存空間把內容複製下來,直到最後一層,再也不有複雜的數據類型,就保持其原引用。這樣,無論數據結構多麼的複雜,數據之間的修改都不會相互影響
進程:一個程序在操做系統中被執行之後就會建立一個進程,經過進程分配資源(cpu、內存、I/O設備),一個進程中會包含一到多個線程,其中有一個線程叫作主線程用於管理其餘線程。一個正在運行的程序能夠看作一個進程,進程擁有獨立運行所須要的所有資源。(例如:打開QQ至關於開啓一個進程)
線程:程序中獨立運行的代碼段。在一個進程執行的過程,通常會分紅不少個小的執行單位,線程就是這些執行單位;在處理機調度,以線程爲單位件進行,多個線程之間併發執行,線程佔用的是cpu。
一個程序至少擁有一個進程,一個進程至少擁有一個線程。進程負責資源的調度和分配,線程纔是程序真正的執行單元,負責代碼的執行。
多線程
多線程定義:多線程是指程序中包含多個執行流,即在一個程序中能夠同時運行多個不一樣的線程來執行不一樣的任務,也就是說容許單個程序建立多個並行執行的線程來完成各自的任務。
多線程優勢:能夠提升CPU的利用率。在多線程程序中,一個線程必須等待的時候,CPU能夠運行其它的線程而不是等待,這樣就大大提升了程序的效率。
因此爲了提升爬蟲的效率,咱們能夠使用多線程來下載文件,在python中咱們使用threading模塊來建立多線程,從而實現多線程爬蟲。(補充:Python3不能再使用thread模塊)。
多線程使用的場合:耗時操做(訪問外存,即:I/O,訪問網絡資源),爲了避免阻礙主線程或者其餘的操做,通常會採用多線程。
對於IO密集型代碼(文件處理,網絡爬蟲),多線程可以有效提高效率(單線程下有IO操做會進行IO等待,會形成沒必要要的時間等待,而開啓多線程後,A線程等待時,會自動切換到線程B,能夠不浪費CPU的資源,從而提高程序執行效率)。
在實際的採集過程當中,既考慮網速和相應的問題,也須要考慮自身機器硬件的狀況,來設置多進程或者多線程。
協程是:在一個線程執行過程當中能夠在一個子程序的預約或者隨機位置中斷,而後轉而執行別的子程序,在適當的時候再返回來接着執行。他自己是一種特殊的子程序或者稱做函數。
遇到IO密集型的業務時,多線程加上協程,你磁盤在那該讀讀該寫寫,我還能去幹點別的。在WEB應用中效果尤其明顯。
協程的好處:
跨平臺
跨體系架構
無需線程上下文切換的開銷
無需原子操做鎖定及同步的開銷
方便切換控制流,簡化編程模型
高併發+高擴展性+低成本:一個CPU支持上萬的協程都不是問題。因此很適合用於高併發處理。
並行:多個進程在同一時刻同時進行
併發:多個進程在同一時間段內交替進行 (操做系統大多采用併發機制),根據必定的算法(常見的就是時間片輪詢算法)
new:它是建立對象時調用,會返回當前對象的一個實例,能夠用_new_來實現單例
init:它是建立對象後調用,對當前對象的一些實例初始化,無返回值
網絡數據包 urllib、urllib2、requests
解析包 re、xpath、beautiful soup、lxml
使用性能更好的機器
使用光纖網絡
多進程
多線程
分佈式
(1)增長併發
默認scrapy開啓的併發線程爲32個, 能夠適當進行增長. 在settings配置文件中修改`CONCURRENT_REQUESTS = 100值爲100, 併發設置成了爲100.
(2)下降日誌級別
在運行scrapy時, 會有大量日誌信息的輸出, 爲了減小CPU的使用率. 能夠設置log輸出信息爲INFO或者ERROR. 在配置文件中編寫: LOG_LEVEL = ‘INFO’
(3)禁止cookie
若是不是真的須要cookie, 則在scrapy爬取數據時能夠禁止cookie從而減小CPU的使用率, 提高爬取效率. 在配置文件中編寫: COOKIES_ENABLED = False.
(4)禁止重試
對失敗的HTTP進行從新請求(重試)會減慢爬取速度, 所以能夠禁止重試. 在配置文件中編寫: RETRY_ENABLED = False
(5)減小下載超時
若是對一個很是慢的連接進行爬取, 減小下載超時能夠能讓卡住的連接快速被放棄, 從而提高效率. 在配置文件中進行編寫: DOWNLOAD_TIMEOUT = 10 超時時間爲10s.
因爲網絡異常的存在,分佈式系統中請求結果存在「三態」的概念,即三種狀態:「成功」、「失敗」、「超時(未知)」
當出現「超時」時能夠經過發起讀取數據的操做以驗證 RPC 是否成功(例如銀行系統的作法)
另外一種簡單的作法是,設計分佈式協議時將執行步驟設計爲可重試的,即具備所謂的「冪等性」
InnoDB:
InnoDB是一個健壯的事務型存儲引擎,這種存儲引擎已經被不少互聯網公司使用,爲用戶操做很是大的數據存儲提供了一個強大的解決方案。
在如下場合下,使用InnoDB是最理想的選擇:
1.更新密集的表。InnoDB存儲引擎特別適合處理多重併發的更新請求。
2.事務。InnoDB存儲引擎是支持事務的標準MySQL存儲引擎。
3.自動災難恢復。與其它存儲引擎不一樣,InnoDB表可以自動從災難中恢復。
4.外鍵約束。MySQL支持外鍵的存儲引擎只有InnoDB。
5.支持自動增長列AUTO_INCREMENT屬性。
通常來講,若是須要事務支持,而且有較高的併發讀取頻率,InnoDB是不錯的選擇。
MEMORY:
使用MySQL Memory存儲引擎的出發點是速度。爲獲得最快的響應時間,採用的邏輯存儲介質是系統內存。
雖然在內存中存儲表數據確實會提供很高的性能,但當mysqld守護進程崩潰時,全部的Memory數據都會丟失。
得到速度的同時也帶來了一些缺陷。
通常在如下幾種狀況下使用Memory存儲引擎:
1.目標數據較小,並且被很是頻繁地訪問。在內存中存放數據,因此會形成內存的使用,能夠經過參數max_heap_table_size控制Memory表的大小,設置此參數,就能夠限制Memory表的最大大小。
2.若是數據是臨時的,並且要求必須當即可用,那麼就能夠存放在內存表中。
3.存儲在Memory表中的數據若是忽然丟失,不會對應用服務產生實質的負面影響。
什麼是RESTful
全稱:Representational State Transfer
是HTTP協議(1.0和1.1)的主要設計者Roy Thomas Fielding提出
資源(Resources) 表現層(Representational )狀態轉化(State Transfer)
是實現API的一種風格
RESTful風格
Resources(資源):使用URL指向一個實體,例如:網頁是資源,媒體也是資源
Representational (表現層):資源的表現形式,例如:圖片,HTML文本等
State Transfer(狀態轉化):GET, POST, PUT, DELETE HTTP動詞操做資源
例如後端的增刪改查,增刪改查能夠和http請求聯繫起來
經常使用HTTP動詞
RESTful解釋:
GET, POST, PUT, DELETE 分別用來 獲取,新建,更新,刪除資源
冪等性:GET, PUT, DELETE
冪等性是指不管一次仍是屢次操做都具備同樣的反作用
POST不具備冪等性,由於post每次都建立一個新的,
對於冪等性操做能夠咱們能夠放心的發屢次操做
對於非冪等性我,咱們須要在後臺保證發送屢次不會建立屢次
Tornado RESTful Api示例
MVC框架:
M:model表示操做數據庫層
V:view表示視圖層
C:controller 表示業務邏輯層
咱們省略視圖層,來實現微服務,進行用戶管理(增刪改查)
cs = int(input('請輸入層數:'))for i in range(cs): j = 1 while j<=2*i+1: print('*',end='') j+=1 print()
i = int(input('請輸入一個整數:')) j = 0while i>0: j = j*10+i%10 i//=10print(j)
a = [1, 1, 5, 2, 5, 2, 5, 2, 6,] b = set(a)for i in b: print(i,a.count(i))
- LEGB法則
L-----LOCAL 局部
E-------ENCLOSE------嵌套做用域
G-------GLOBLE-------全局
B---------BUILT-IN------內置
a = 100b = 2c = 10def waibu(): b=200 c=2 def neibu(): c=300 print(c)#LOCAL局部變量 print(b)#ENCLOSE嵌套 print(a)#GLOBAL全局 print(max)#BUILT-IN內置 neibu() waibu()
def jiecheng(n): if n==1: return 1 else: return n*jiecheng(n-1) s=jiecheng(5)print(s)
a=[lambda x:x*i for i in range(3)]print(a[0](3)) # 6print(a[1](3)) # 6print(a[2](3)) # 6
class A(): def __init__(self): print('A開始') print('A結束')class B(A): def __init__(self): print('B開始') super().__init__() print('B結束')class C(A): def __init__(self): print('C開始') super().__init__() print('C結束')class D(B, C): def __init__(self): print('D開始') super().__init__() print('D結束') d = D()
輸出結果爲:
D開始
B開始
C開始
A開始
A結束
C結束
B結束
D結束
class Car(): def __new__(cls, *args, **kwargs): if not hasattr(Car,'inst'):#若是Car裏面沒有inst屬性 Car.inst=object.__new__(Car)#就創建一個Car對象,給inst屬性 return Car.inst#返回一個屬性inst def __init__(self,name,cid): print('你好') self.name=name self.cid=cid a=Car('寶馬','京A66666') b=Car('奔馳','京B66666')print(a.name,a.cid)print(b.name,b.cid)輸出: 你好 你好 奔馳 京B66666 奔馳 京B66666
class A(): def j(self): print('aaa')class B(): def j(self): print('bbb')class C(): def j(self): print('ccc')def e(d): d.j() f=A() g=B() k=C() e(f) e(g) e(k)
class Resi(): def __init__(self): self.obsv=[] self.stautus='' def attach(self,ob): self.obsv.append(ob) def notify(self): for x in self.obsv: x.update()class Observe(): def __init__(self,name,rs): self.name=name self.rs=rs def update(self): print('%s %s 請不要打遊戲了'%(self.rs.status,self.name))class Manager(): def __init__(self,name,boss): self.name=name self.boss=boss def update(self): print('%s %s 請到北京飯店開會'%(self.boss.status,self.name))if __name__=='__main__': resi=Resi() obj_zs=Observe('張三',resi) obj_ls=Observe('李四',resi) obj_xh=Observe('小紅',resi) m_lqd=Manager('劉強東',resi) m_my=Manager('馬雲',resi) resi.attach(obj_zs) resi.attach(obj_ls) resi.attach(obj_xh) resi.attach(m_lqd) resi.attach(m_my) resi.status='老闆來啦'resi.notify()
class CashNormal(): def accept_money(self,money): return moneyclass CashRate(): def __init__(self,rate): self.rate=rate def accept_money(self,money): return money*self.rateclass CashReturn(): def __init__(self,conditon,ret): self.conditon=conditon self.ret=ret def accept_money(self,money): return money-(money//self.conditon)*self.retclass Context(): def __init__(self,cs): self.cs=cs def get_result(self,money): return self.cs.accept_money(money)if __name__ == '__main__': zd={} zd[1]=Context(CashNormal()) zd[2]=Context(CashRate(0.8)) zd[3]=Context(CashReturn(300,50)) celue=int(input('請輸入策略')) if celue in zd.keys(): cs=zd[celue] else: cs=zd[1] money=float(input('請輸入金額'))print(cs.get_result(money))
class Bmw(): def __init__(self,name): self.name=nameclass Benz(): def __init__(self,name): self.name=nameclass Carfactory: @staticmethod def makecar(name): if name=='寶馬': return Bmw(name) elif name=='奔馳': return Benz(name) car=Carfactory.makecar('寶馬')print(car.name,type(car)) car1=Carfactory.makecar('奔馳')print(car1.name,type(car1))
class A(): count=0 def __init__(self,name): self.name=name A.count+=1 print('加上',self.name,'還有%d個對象'%A.count) def __del__(self): A.count-=1 print('刪除',self.name,'還剩%d個對象'%A.count) a=A('張三') b=A('李四')del adel b
# 重要前提:二分查找的前提是有序
# 例如:【2,5,1,4,1,3】
# 先排序:【1,1,2,3,4,5】
# 先拿出列表中間的那個元素,和num進行比較,若是num大於中間的那個元素,
# 則代表:應該下次在中間和末尾之間的元素查找
# 若是num小於中間的這個元素,則代表:num在開始的元素和中間元素之間
list_1=[2,5,1,4,1,3] list_1.sort()print("排序以後的列表:",list_1) num=int(input("請輸入你要查找的數字:")) first=0last=len(list_1)-1while first<last: mid=(first+last)//2 if list_1[mid]==num: print("找到了") break elif list_1[mid]>num: last=mid-1 elif list_1[mid]<num: first=mid+1else: print("沒找到") list_1.sort()print("拍完序以後的列表爲:",list_1) num=int(input("請輸入你要查找的數字:")) first=0last=len(list_1)-1while first<last: mid=(first+last)//2 if list_1[mid]==num: print("找到啦") break elif list_1[mid]<num: first=mid+1 elif list_1[mid]>num: last=mid-1else: print("誰知道在哪")
冒泡排序算法的運做以下:
比較相鄰的元素。若是第一個比第二個大(升序),就交換他們兩個。
對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對。這步作完後,最後的元素會是最大的數。
針對全部的元素重複以上的步驟,除了最後一個。
持續每次對愈來愈少的元素重複上面的步驟,直到沒有任何一對數字須要比較。
list_1=[2,3,1,5,6,4] gs=len(list_1)for i in range(0,gs-1): for j in range(0,gs-i-1): if list_1[j]>list_1[j+1]: list_1[j],list_1[j+1]=list_1[j+1],list_1[j]print(list_1)
cs = int(input("請輸入要打印的層數:"))for i in range(cs): for j in range(cs-i-1): print(' ',end='') for k in range(2*i+1): if k==0 or k==2*i or i==cs-1:#條件控制輸出的空心塔型 print('*',end='') else: print(' ',end='') i+=1 print()
請輸出要打印的層數7
*
* *
* *
* *
* *
* *
*************
cs = int(input("請輸入須要打印的層數:"))for i in range(cs): for j in range(cs-i-1): print(' ',end='') for k in range(2*i+1):#這裏的範圍取值決定了塔型每行的字符數 print('*',end='') i+=1 print()
輸出:
*
***
*****
*******
*********
***********
*************
***************
①列表:list=[val1,val2,val3,val4] ②元組:tuple=(val1,val2,val3,val4) ③字典:dict={key1:val1,key2:val2} ④集合:set={val1,val2,val3,val4}
簡要描述 Python 中單引號、雙引號、三引號的區別。
①單引號中能夠使用雙引號,中間的會當作字符串輸出
②雙引號中能夠使用單引號,中間的會當作字符串輸出
Global VarName
1.賦值: 只是複製了新對象的引用,不會開闢新的內存空間。 2.淺拷貝: 建立新對象,其內容是原對象的引用。 淺拷貝有三種形式:切片操做,工廠函數,copy模塊中的copy函數。 如: lst = [1,2,3,[4,5]] 切片操做:lst1 = lst[:] 或者 lst1 = [each for each in lst] 工廠函數:lst1 = list(lst) copy函數:lst1 = copy.copy(lst)
淺拷貝之因此稱爲淺拷貝,是它僅僅只拷貝了一層,在lst中有一個嵌套的list[4,5],若是咱們修改了它,狀況就不同了。
3.深拷貝:只有一種形式,copy模塊中的deepcopy函數。 和淺拷貝對應,深拷貝拷貝了對象的全部元素,包括多層嵌套的元素。 深拷貝出來的對象是一個全新的對象,再也不與原來的對象有任何關聯。
若是 custname 字符串的內容爲 utf-8 的字符,如何將 custname 的內容轉爲 gb18030 的字符串?
custname = custname.decode(‘utf-8’).encode(‘b18030’)
②利用集合set特性,元素是非重複的
a = [1,2,3,4,5,1,2,3]def fun1(a): a=list(set(a)) print(a) fun1(a)
①利用字典的from keys來自動過濾重複值
a = [1, 2, 3, 4, 5, 1, 2, 3]def fun1(a): b = {} b = b.fromkeys(a) c = list(b.keys()) print(c) fun1(a)
首先,我想說的是*args和**kwargs並非必須這樣寫,只有前面的*和**纔是必須的。你能夠寫成*var和**vars。而寫成*args和**kwargs只是約定俗稱的一個命名規定。
*args和*kwargs主要用於函數定義,你能夠將不定量的參數傳遞給一個參數。其中*args是用來發送一個非鍵值對的可變數量的參數列表給一個函數;**kwargs
容許你將不定長度的鍵值對, 做爲參數傳遞給一個函數。 若是你想要在一個函數裏處理帶名字的參數, 你應該使用**kwargs
。
這裏傳遞了3個參數,按位置傳參,'123'爲test傳參,'hello'和'2019'爲*args傳參,這裏傳了2個參數。
def import_args(test, *args): print('param1', test) for item in args: print('other param', item) import_args('123', 'hello', '2019')
注意,看下面的*args的另外一種用法:用來解壓數據。
def import_args(test, *args):
print('param1', test)
for item in args:
print('other param', item)
args = ['hello', '2019']
import_args('123', *args)
輸出結果:
1 param1 123
2 other param hello
3 other param 2019
這段代碼和上面的效果是同樣的,可是這裏第8行的*args和第1行的*args但是不同的。第一行是表示函數能夠接受不定數量的非鍵值對的參數,用來傳參使用的。第八行是用來解壓列表
['hello', '2019']的每一項數據的,用來解壓參數的。這是*args的兩種用法,也可說是*的兩種用法,由於args是可變的。
接下來講說**kwargs。
def import_kwargs(test, **kwargs):
print('param1', test)
for key, value in kwargs.items():
print(key, value)
d = {'name': 'jack', 'age': 26}
import_kwargs('123', **d)
**kwargs用來傳遞帶鍵值對的參數,而**也是用來解壓字典容器內的參數。
輸出結果:
param1 123
name jack
age 26
總結:*args和**kwargs都是用於函數中傳遞參數的,*args傳遞的是非鍵值對的參數,**kwargs傳遞的是帶鍵值對的參數,若是還有普通參數須要傳遞,那麼應該先傳遞普通的參數。
a=['apple', 'banana', 'apple', 'tomato', 'orange', 'apple', 'banana', 'watermeton']
方法一:
利用字典
1 a = ['apple', 'banana', 'apple', 'tomato', 'orange', 'apple', 'banana', 'watermeton']2 dic = {}3 for key in a:4 dic[key] = dic.get(key, 0) + 15 print(dic)
輸出結果:
1 {'apple': 3, 'banana': 2, 'tomato': 1, 'orange': 1, 'watermeton': 1}
方法二:
利用python的collections包。
1 from collections import Counter2 3 a = ['apple', 'banana', 'apple', 'tomato', 'orange', 'apple', 'banana', 'watermeton']4 d = Counter(a)5 print(d)
輸出結果:
1 Counter({'apple': 3, 'banana': 2, 'tomato': 1, 'orange': 1, 'watermeton': 1}) # 是一個相似字典的結構
alist=[{"name":"a", "age":20}, {"name":"b", "age":30}, {"name":"c", "age":25}],將 alist 中的元素按照 age 從大到小排序。
利用list的內建函數,list.sort()來進行排序。
1 alist = [{"name": "a", "age": 20}, {"name": "b", "age": 30}, {"name": "c", "age": 25}]2 alist.sort(key=lambda x: x['age'])3 print(alist)
這是一種效率很高的排序方法。
輸出結果:
1 [{'name': 'a', 'age': 20}, {'name': 'c', 'age': 25}, {'name': 'b', 'age': 30}]
1 a = 12 def fun(a):3 a = 24 fun(a)5 print(a)1
分析,在函數外面定義了一個全局變量a爲1,在函數內部定義了一個局部變量a爲2。局部變量在離開函數後就失效了。
因此,結果爲全局變量的a的值。若是在a=2以前加上global a,聲明爲全局變量,那麼結果爲2。
1 a = []2 def fun(a):3 a.append(1)4 fun(a)5 print(a)[1]這是由於,將a傳入到function中,這至關於對a進行賦值引用。因爲a是可變類型的,因此在函數內部修改a的時候,外部的全局變量a也跟着變化。1 class Person:2 name = 'Lily'3 4 p1 = Person()5 p2 = Person()6 p1.name = 'Bob'7 print(p1.name)8 print(p2.name)9 print(Person.name)
Bob,Lily,Lily
a = ['a', 'b', 'c', 'd', 'e'] b = [1, 2, 3, 4, 5] dic=dict(zip(a,b)) print(dic)
使用 python 已有的數據結構,簡單的實現一個棧結構。
class Stack(object): def __init__(self,size): self.size=size self.stack = [] self.top = 0 # 初始化,top=0是則爲空棧 def push(self,x): if self.stackFull():# 進棧以前檢查棧是否已滿 raise Exception("overflow") else: self.stack.append(x) self.top=self.top+1 #push進去的第一個元素爲下標爲1 def pop(self): if self.stackEmpty(): raise Exception('underflow!') else: self.top=self.top-1 return self.stack.pop()#利用Python內建函數pop()實現彈出 def stackEmpty(self): if self.top ==0: return True else: return False def stackFull(self): if self.top == self.size: return True else: return False if __name__=='__main__': s=Stack(10) for i in range(9): s.push(i) s.pop() print(s.top) print(s.size) print(s.stack)
驗證碼
去重:https://www.cnblogs.com/518894-lu/p/9119559.html
清洗:https://blog.csdn.net/a13526863959/article/details/84587143,
https://blog.csdn.net/wanght89/article/details/78188591
# _*_ coding:UTF-8 _*_ from click._compat import raw_input def find(list,a): for i in range(1,len(list)): if list[i]==a: print(i) else: return None find(raw_input('請輸入列表:'),raw_input('請輸入要查找的元素:'))
解決方法2: 使用python的內建函數enumerate
enumerate() 解析:同時枚舉出序列的下標和值,這個是一個很是有用的函數,能夠避免不少醜陋的代碼
# _*_ coding:UTF-8 _*_ from click._compat import raw_input def find(list,a): for i,item in enumerate(list): if item==a: print(i) else: return None find(raw_input('請輸入列表:'),raw_input('請輸入要查找的元素:'))
利用sum()函數求和
print(sum(range(0,101)))
5050
利用global 修改全局變量
a = 5 def fn(): global a a=4 fn() print(a)4
os:提供了很多與操做系統相關聯的函數
sys: 一般用於命令行參數
re: 正則匹配
math: 數學運算
datetime:處理日期時間
del和update方法
dic = {'height':'28','age':'12'}del dic['age']print(dic) {'height': '28'} dic.update({'name':'22'})print(dic) {'height': '28', 'name': '22'}
GIL 是python的全局解釋器鎖,同一進程中假若有多個線程運行,一個線程在運行python程序的時候會霸佔python解釋器(加了一把鎖即GIL),使該進程內的其餘線程沒法運行,等該線程運行完後其餘線程才能運行。若是線程運行過程當中遇到耗時操做,則解釋器鎖解開,使其餘線程運行。因此在多線程中,線程的運行還是有前後順序的,並非同時進行。
多進程中由於每一個進程都能被系統分配資源,至關於每一個進程有了一個python解釋器,因此多進程能夠實現多個進程的同時運行,缺點是進程系統資源開銷大
先經過集合去重,再轉列表
list = [1,5,8,8,2,1,1,5,2,1,1,1] a= set(list)print(a) {8, 1, 2, 5} b = [x for x in a]print(b) [8, 1, 2, 5]
首先,我想說的是*args和**kwargs並非必須這樣寫,只有前面的*和**纔是必須的。你能夠寫成*var和**vars。而寫成*args和**kwargs只是約定俗稱的一個命名規定。
*args和*kwargs主要用於函數定義,你能夠將不定量的參數傳遞給一個參數。這裏的不定的意思是:預先並不知道函數使用者會傳遞多少個參數給你,因此在這個場景下使用者兩個關鍵字。其中*args是用來發送一個非鍵值對的可變數量的參數列表給一個函數;**kwargs
容許你將不定長度的鍵值對, 做爲參數傳遞給一個函數。 若是你想要在一個函數裏處理帶名字的參數, 你應該使用**kwargs
。
python2返回列表,python3返回迭代器,節約內存
函數能夠做爲參數傳遞的語言,能夠使用裝飾器
整型--int
布爾型--bool
字符串--str
列表--list
元組--tuple
字典—dict
__init__是初始化方法,建立對象後,就馬上被默認調用了,可接收參數,以下
class Bike: def __init__(self,newWheelNum,NewColor): self.wheelNum = newWheelNum self.color = NewColor #__init__方法自動被調回,能夠建立對象接受參數 def move(self): print('車會跑') #建立對象 BM = Bike(2,'green') print('車的顏色爲:%s' %BM.color) print('車的輪子數量爲:%d' %BM.wheelNum) 車的顏色爲:green 車的輪子數量爲:2 #只打印__init__方法執行的結果,move方法未執行
一、__new__至少要有一個參數cls,表明當前類,此參數在實例化時由Python解釋器自動識別
二、__new__必需要有返回值,返回實例化出來的實例,這點在本身實現__new__時要特別注意,能夠return父類(經過super(當前類名, cls))__new__出來的實例,或者直接是object的__new__出來的實例
三、__init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上能夠完成一些其它初始化的動做,__init__不須要返回值
四、若是__new__建立的是當前類的實例,會自動調用__init__函數,經過return語句裏面調用的__new__函數的第一個參數是cls來保證是當前類實例,若是是其餘類的類名,;那麼實際建立返回的就是其餘類的實例,其實就不會調用當前類的__init__函數,也不會調用其餘類的__init__函數。
class A(object): def __init__(self): print('這是init方法',self) def __new__(cls): print('這是cls的ID:',id(cls)) print('這是new方法',object.__new__(cls)) return object.__new__(cls) A()print('這是類A的ID:',id(A))這是cls的ID: 47677960 #cls和類ID同樣,說明指向同一個類,也就是cla就是建立的實例類這是new方法 <__main__.A object at 0x00307350>#init方法中的self和new方法返回值地址同樣這是init方法 <__main__.A object at 0x00307350>#說明返回值是對象這是類A的ID: 47677960#cls和類ID同樣,說明指向同一個類,也就是cla就是建立的實例類
打開文件在進行讀寫的時候可能會出現一些異常情況,若是按照常規的f.open寫法,咱們須要try,except,finally,作異常判斷,而且文件最終無論遇到什麼狀況,都要執行finally f.close()關閉文件
f = open("./1.txt",'wb')try: f.writ("hello world")except: pass finally: f.close()
with方法幫咱們實現了finally中f.close(固然還有其餘自定義功能,有興趣能夠研究with方法源碼)
with open('/path/to/file', 'r') as f: print(f.read())
map()函數第一個參數是fun,第二個參數是通常是list,第三個參數能夠寫list,也能夠不寫,根據需求
list = [1,2,3,4,5]def fn(x): return x**2res = map(fn,list) res = [i for i in res if i >10]print(res) [16, 25]
隨機整數:random.randint(a,b),生成區間內的整數
隨機小數:習慣用numpy庫,利用np.random.randn(5)生成5個隨機小數
0-1隨機小數:random.random(),括號中不傳參
import random import numpy as np result = random.randint(10,20)#區間 res = np.random.randn(5) ret = random.random()#不能傳數值 print('正整數:',result) print('5個隨機小數:',res) print('0-1隨機小數;',ret) 正整數: 14 5個隨機小數: [-0.67833428 1.53692927 0.33841477 -1.24463382 -0.27630526] 0-1隨機小數; 0.2925398128464497
r , 表示須要原始字符串,不轉義特殊字符
import re str = '<div class="nam">中國</div>'re = re.findall(r'<div class=".*">(.*?)</div>',str)#".*"中 .表明無關緊要,*表明任意字符,知足類名能夠變化,(.*?)提取文本print(re) ['中國']
assert()方法,斷言成功,則程序繼續執行,斷言失敗,則程序報錯
a=3assert (a>1)print("斷言成功,程序繼續向下執行") b=4assert (b>7)print("斷言失敗,程序報錯")
斷言成功,程序繼續向下執行
Traceback (most recent call last):
File "F:/items/生成器.py", line 6, in <module>
assert (b>7)
AssertionError
select distinct name from student
ls pwd cd touch rm mkdir tree cp mv cat more grep echo
一、Python3 使用 print 必需要以小括號包裹打印內容,好比 print('hi')
Python2 既能夠使用帶小括號的方式,也能夠使用一個空格來分隔打印內容,好比 print 'hi'
二、python2 range(1,10)返回列表,python3中返回迭代器,節約內存
三、python2中使用ascii編碼,python3中使用utf-8編碼
四、python2中unicode表示字符串序列,str表示字節序列,
python3中str表示字符串序列,byte表示字節序列
五、python2中爲正常顯示中文,引入coding聲明,python3中不須要
六、python2中是raw_input()函數,python3中是input()函數
不可變數據類型:數值型、字符串型string和元組tuple
不容許變量的值發生變化,若是改變了變量的值,至關因而新建了一個對象,而對於相同的值的對象,在內存中則只有一個對象(一個地址),以下圖用id()方法能夠打印對象的id
a = 3b = 4print(id(a))print(id(b))2012993360 2012993376
可變數據類型:列表list和字典dict;
容許變量的值發生變化,即若是對變量進行append、+=等這種操做後,只是改變了變量的值,而不會新建一個對象,變量引用的對象的地址也不會變化,不過對於相同的值的不一樣對象,在內存中則會存在不一樣的對象,即每一個對象都有本身的地址,至關於內存中對於同值的對象保存了多份,這裏不存在引用計數,是實實在在的對象。
a = [3] b = {'value':'4'}print(id(a))print(id(b)) a.append(4) b.update({'key':'3'})print(a,id(a))print(b,id(b))59785944 58015056[3, 4] 59785944{'value': '4', 'key': '3'} 58015056
set去重,去重轉成list,利用sort方法排序,reverse=False是從小到大排
s = "ajldjlajfdljfddd"s1 = set(s)print(s1) s=list(s1)print(s) s.sort(reverse=False)print(s) res = "".join(s)print(res) {'d', 'f', 'j', 'a', 'l'} ['d', 'f', 'j', 'a', 'l'] ['a', 'd', 'f', 'j', 'l']
adfjl
sum = lambda a,b:a*b #表達式print(sum(5,4))#參數20
dict={"name":"zs","age":18,"city":"深圳","tel":"1362626627"}
dict={"name":"zs","age":18,"city":"深圳","tel":"1362626627"} list = sorted(dict.items(),key=lambda i:i[0],reverse=False)#dict.items()結果是字典的鍵值對元組 #i[0]表示鍵,i[1]表示值,經過lambda函數根據鍵排序print("sorted根據字典鍵排序:",list) new_dict={}for i in list: new_dict[i[0]]=i[1]print("新字典:",new_dict) sorted根據字典鍵排序: [('age', 18), ('city', '深圳'), ('name', 'zs'), ('tel', '1362626627')]新字典: {'age': 18, 'city': '深圳', 'name': 'zs', 'tel': '1362626627'}
from collections import Counter a = "kjalfj;ldsjafl;hdsllfdhg;lahfbl;hl;ahlf;h"res = Counter(a)print(res) Counter({'l': 9, ';': 6, 'h': 6, 'f': 5, 'a': 4, 'j': 3, 'd': 3, 's': 2, 'k': 1, 'g': 1, 'b': 1})
import re a = 'not 404 found 張三 99 深圳'list = a.split(" ")print(list) res = re.findall('\d+|[a-zA-Z]+',a)#鏈接多個匹配方式,先匹配數字,再匹配單詞print(res)for i in res: if i in list: list.remove(i) new_str = " ".join(list)print(new_str) ['not', '404', 'found', '張三', '99', '深圳'] ['not', '404', 'found', '99']張三 深圳
順便貼上匹配小數的代碼,雖然能匹配,可是健壯性有待進一步確認
import re a = 'not 404 50.56 found 張三 99 深圳'list = a.split(" ")print(list) res = re.findall('\d+\.?\d*|[a-zA-Z]+',a)#鏈接多個匹配方式,先匹配數字,再匹配小數,再匹配單詞print(res)for i in res: if i in list: list.remove(i) new_str = " ".join(list)print(new_str) ['not', '404', '50.56', 'found', '張三', '99', '深圳'] ['not', '404', '50.56', 'found', '99']張三 深圳
filter() 函數用於過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表。該接收兩個參數,第一個爲函數,第二個爲序列,序列的每一個元素做爲參數傳遞給函數進行判,而後返回 True 或 False,最後將返回 True 的元素放到新列表
re.compile是將正則表達式編譯成一個對象,加快速度,並重復使用
extend能夠將另外一個集合中的元素逐一添加到列表中,區別於append總體添加
python:os.remove(文件名)
linux: rm 文件名
順便把星期的代碼也貼上了
外鍵、索引、聯合查詢、選擇特定字段等等
pychart、matplotlib
自定義異經常使用raise拋出異常
(.*)是貪婪匹配,會把知足正則的儘量多的日後匹配
(.*?)是非貪婪匹配,會把知足正則的儘量少匹配
ORM,全拼Object-Relation Mapping,意爲對象-關係映射
實現了數據模型與數據庫的解耦,經過簡單的配置就能夠輕鬆更換數據庫,而不須要修改代碼只須要面向對象編程,orm操做本質上會根據對接的數據庫引擎,翻譯成對應的sql語句,全部使用Django開發的項目無需關心程序底層使用的是MySQL、Oracle、sqlite....,若是數據庫遷移,只須要更換Django的數據庫引擎便可
列表推導式的騷操做
運行過程:for i in a ,每一個i是【1,2】,【3,4】,【5,6】,for j in i,每一個j就是1,2,3,4,5,6,合併後就是結果
還有更騷的方法,將列表轉成numpy矩陣,經過numpy的flatten()方法,代碼永遠是隻有更騷,沒有最騷
join()括號裏面的是可迭代對象,x插入可迭代對象中間,造成字符串,結果一致,有沒有忽然感受字符串的常見操做都不會玩了
順便建議你們學下os.path.join()方法,拼接路徑常常用到,也用到了join,和字符串操做中的join有什麼區別,該問題你們能夠查閱相關文檔,後期會有答案
try..except..else沒有捕獲到異常,執行else語句
try..except..finally無論是否捕獲到異常,都執行finally語句
zip()函數在運算時,會以一個或多個序列(可迭代對象)作爲參數,返回一個元組的列表。同時將這些序列中並排的元素配對。
zip()參數能夠接受任何類型的序列,同時也能夠有兩個以上的參數;當傳入參數的長度不一樣時,zip能自動以最短序列長度爲準進行截取,得到元組。
show databases;
show tables;
desc 表名;
select * from 表名;
delete from 表名 where id=5;
update students set gender=0,hometown="北京" where id=5
兩個列表相加,等價於extend
一、使用生成器,由於能夠節約大量內存
二、循環代碼優化,避免過多重複代碼的執行
三、核心模塊用Cython PyPy等,提升效率
四、多進程、多線程、協程
五、多個if elif條件判斷,能夠把最有可能先發生的條件放到前面寫,這樣能夠減小程序判斷的次數,提升效率
redis: 內存型非關係數據庫,數據保存在內存中,速度快
mysql:關係型數據庫,數據保存在磁盤中,檢索的話,會有必定的Io操做,訪問速度相對慢
一、細節上的錯誤,經過print()打印,能執行到print()說明通常上面的代碼沒有問題,分段檢測程序是否有問題,若是是js的話能夠alert或console.log
二、若是涉及一些第三方框架,會去查官方文檔或者一些技術博客。
三、對於bug的管理與歸類總結,通常測試將測試出的bug用teambin等bug管理工具進行記錄,而後咱們會一條一條進行修改,修改的過程也是理解業務邏輯和提升本身編程邏輯縝密性的方法,我也都會收藏作一些筆記記錄。
四、導包問題、城市定位多音字形成的顯示錯誤問題
url='https://sycm.taobao.com/bda/tradinganaly/overview/get_summary.json?dateRange=2018-03-20%7C2018-03-20&dateType=recent1&device=1&token=ff25b109b&_=1521595613462'
仍有同窗問正則,其實匹配並不難,提取一段特徵語句,用(.*?)匹配便可
利用min()方法求出最小值,原列表刪除最小值,新列表加入最小值,遞歸調用獲取最小值的函數,反覆操做
由於建立對象時__new__方法執行,而且必須return 返回實例化出來的對象所cls.__instance是否存在,不存在的話就建立對象,存在的話就返回該對象,來保證只有一個實例對象存在(單列),打印ID,值同樣,說明對象同一個
題目自己只有a="%.03f"%1.3335,讓計算a的結果,爲了擴充保留小數的思路,提供round方法(數值,保留位數)
fn("one",1)直接將鍵值對傳給字典;
fn("two",2)由於字典在內存中是可變數據類型,因此指向同一個地址,傳了新的額參數後,會至關於給字典增長鍵值對
fn("three",3,{})由於傳了一個新字典,因此再也不是原先默認參數的字典
200 OK
請求正常處理完畢
204 No Content
請求成功處理,沒有實體的主體返回
206 Partial Content
GET範圍請求已成功處理
301 Moved Permanently
永久重定向,資源已永久分配新URI
302 Found
臨時重定向,資源已臨時分配新URI
303 See Other
臨時重定向,指望使用GET定向獲取
304 Not Modified
發送的附帶條件請求未知足
307 Temporary Redirect
臨時重定向,POST不會變成GET
400 Bad Request
請求報文語法錯誤或參數錯誤
401 Unauthorized
須要經過HTTP認證,或認證失敗
403 Forbidden
請求資源被拒絕
404 Not Found
沒法找到請求資源(服務器無理由拒絕)
500 Internal Server Error
服務器故障或Web應用故障
503 Service Unavailable
服務器超負載或停機維護
該題目網上有不少方法,我不想截圖網上的長串文字,看的頭疼,按我本身的理解說幾點
前端優化:
一、減小http請求、例如製做精靈圖
二、html和CSS放在頁面上部,javascript放在頁面下面,由於js加載比HTML和Css加載慢,因此要優先加載html和css,以防頁面顯示不全,性能差,也影響用戶體驗差
後端優化:
一、緩存存儲讀寫次數高,變化少的數據,好比網站首頁的信息、商品的信息等。應用程序讀取數據時,通常是先從緩存中讀取,若是讀取不到或數據已失效,再訪問磁盤數據庫,並將數據再次寫入緩存。
二、異步方式,若是有耗時操做,能夠採用異步,好比celery
三、代碼優化,避免循環和判斷次數太多,若是多個if else判斷,優先判斷最有可能先發生的狀況
數據庫優化:
一、若有條件,數據能夠存放於redis,讀取速度快
二、創建索引、外鍵等
InnoDB:支持事務處理,支持外鍵,支持崩潰修復能力和併發控制。若是須要對事務的完整性要求比較高(好比銀行),要求實現併發控制(好比售票),那選擇InnoDB有很大的優點。若是須要頻繁的更新、刪除操做的數據庫,也能夠選擇InnoDB,由於支持事務的提交(commit)和回滾(rollback)。
MyISAM:插入數據快,空間和內存使用比較低。若是表主要是用於插入新記錄和讀出記錄,那麼選擇MyISAM能實現處理高效率。若是應用的完整性、併發性要求比 較低,也能夠使用。
MEMORY:全部的數據都在內存中,數據的處理速度快,可是安全性不高。若是須要很快的讀寫速度,對數據的安全性要求較低,能夠選擇MEMOEY。它對錶的大小有要求,不能創建太大的表。因此,這類數據庫只使用在相對較小的數據庫表。
dict()建立字典新方法
同源策略須要同時知足如下三點要求:
1)協議相同
2)域名相同
3)端口相同
http:www.test.com與https:www.test.com 不一樣源——協議不一樣
http:www.test.com與http:www.admin.com 不一樣源——域名不一樣
http:www.test.com與http:www.test.com:8081 不一樣源——端口不一樣
只要不知足其中任意一個要求,就不符合同源策略,就會出現「跨域」
1,session 在服務器端,cookie 在客戶端(瀏覽器)
二、session 的運行依賴 session id,而 session id 是存在 cookie 中的,也就是說,若是瀏覽器禁用了 cookie ,同時 session 也會失效,存儲Session時,鍵與Cookie中的sessionid相同,值是開發人員設置的鍵值對信息,進行了base64編碼,過時時間由開發人員設置
三、cookie安全性比session差
進程:
一、操做系統進行資源分配和調度的基本單位,多個進程之間相互獨立
二、穩定性好,若是一個進程崩潰,不影響其餘進程,可是進程消耗資源大,開啓的進程數量有限制
線程:
一、CPU進行資源分配和調度的基本單位,線程是進程的一部分,是比進程更小的能獨立運行的基本單位,一個進程下的多個線程能夠共享該進程的全部資源
二、若是IO操做密集,則能夠多線程運行效率高,缺點是若是一個線程崩潰,都會形成進程的崩潰
應用:
IO密集的用多線程,在用戶輸入,sleep 時候,能夠切換到其餘線程執行,減小等待的時間
CPU密集的用多進程,由於假如IO操做少,用多線程的話,由於線程共享一個全局解釋器鎖,當前運行的線程會霸佔GIL,其餘線程沒有GIL,就不能充分利用多核CPU的優點
any():只要迭代器中有一個元素爲真就爲真
all():迭代器中全部的判斷項返回都是真,結果才爲真
python中什麼元素爲假?
答案:(0,空字符串,空列表、空字典、空元組、None, False)
測試all()和any()方法
IOError:輸入輸出異常
AttributeError:試圖訪問一個對象沒有的屬性
ImportError:沒法引入模塊或包,基本是路徑問題
IndentationError:語法錯誤,代碼沒有正確的對齊
IndexError:下標索引超出序列邊界
KeyError:試圖訪問你字典裏不存在的鍵
SyntaxError:Python代碼邏輯語法出錯,不能執行
NameError:使用一個還未賦予對象的變量
一、複製不可變數據類型,無論copy仍是deepcopy,都是同一個地址當淺複製的值是不可變對象(數值,字符串,元組)時和=「賦值」的狀況同樣,對象的id值與淺複製原來的值相同。
二、複製的值是可變對象(列表和字典)
淺拷貝copy有兩種狀況:
第一種狀況:複製的 對象中無 複雜 子對象,原來值的改變並不會影響淺複製的值,同時淺複製的值改變也並不會影響原來的值。原來值的id值與淺複製原來的值不一樣。
第二種狀況:複製的對象中有 複雜 子對象 (例如列表中的一個子元素是一個列表), 改變原來的值 中的複雜子對象的值 ,會影響淺複製的值。
深拷貝deepcopy:徹底複製獨立,包括內層列表和字典
__init__:對象初始化方法
__new__:建立對象時候執行的方法,單列模式會用到
__str__:當使用print輸出對象的時候,只要本身定義了__str__(self)方法,那麼就會打印從在這個方法中return的數據
__del__:刪除對象執行的方法
文件名和參數構成的列表
生成器是特殊的迭代器,
一、列表表達式的【】改成()便可變成生成器
二、函數在返回值得時候出現yield就變成生成器,而不是函數了;
中括號換成小括號便可,有沒有驚呆了
(傳兩個條件,x<0和abs(x))
foo = [{"name":"zs","age":19},{"name":"ll","age":54},
{"name":"wa","age":17},{"name":"df","age":23}]
有沒有發現dic.items和zip(dic.keys(),dic.values())都是爲了構造列表嵌套字典的結構,方便後面用sorted()構造排序規則
當以字符串格式化書寫方式的時候,若是用戶輸入的有;+SQL語句,後面的SQL語句會執行,好比例子中的SQL注入會刪除數據庫demo
解決方式:經過傳參數方式解決SQL注入
|表示或,根據冒號或者空格切分
json.dumps()字典轉json字符串,json.loads()json轉字典
一、InnoDB 支持事務,MyISAM 不支持,這一點是很是之重要。事務是一種高
級的處理方式,如在一些列增刪改中只要哪一個出錯還能夠回滾還原,而 MyISAM
就不能夠了;
二、MyISAM 適合查詢以及插入爲主的應用,InnoDB 適合頻繁修改以及涉及到
安全性較高的應用;
三、InnoDB 支持外鍵,MyISAM 不支持;
四、對於自增加的字段,InnoDB 中必須包含只有該字段的索引,可是在 MyISAM
表中能夠和其餘字段一塊兒創建聯合索引;
五、清空整個表時,InnoDB 是一行一行的刪除,效率很是慢。MyISAM 則會重
建表;
python垃圾回收主要以引用計數爲主,標記-清除和分代清除爲輔的機制,其中標記-清除和分代回收主要是爲了處理循環引用的難題。
引用計數算法
當有1個變量保存了對象的引用時,此對象的引用計數就會加1
當使用del刪除變量指向的對象時,若是對象的引用計數不爲1,好比3,那麼此時只會讓這個引用計數減1,即變爲2,當再次調用del時,變爲1,若是再調用1次del,此時會真的把對象進行刪除
int("1.4")報錯,int(1.4)輸出1
一、頂級定義之間空兩行,好比函數或者類定義。
二、方法定義、類定義與第一個方法之間,都應該空一行
三、三引號進行註釋
四、使用Pycharm、Eclipse通常使用4個空格來縮進代碼
findall結果無需加group(),search須要加group()提取
悲觀鎖, 就是很悲觀,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會block直到它拿到鎖。傳統的關係型數據庫裏邊就用到了不少這種鎖機制,好比行鎖,表鎖等,讀鎖,寫鎖等,都是在作操做以前先上鎖。
樂觀鎖,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,能夠使用版本號等機制,樂觀鎖適用於多讀的應用類型,這樣能夠提升吞吐量
模式較多,比較下背背記記便可
Linux 容許將命令執行結果 重定向到一個 文件
將本應顯示在終端上的內容 輸出/追加 到指定文件中
> 表示輸出,會覆蓋文件原有的內容
>> 表示追加,會將內容追加到已有文件的末尾
用法示例:
將 echo 輸出的信息保存到 1.txt 裏echo Hello Python > 1.txt 將 tree 輸出的信息追加到 1.txt 文件的末尾tree >> 1.txt
前面的<>和後面的<>是對應的,能夠用此方法
Python中函數參數是引用傳遞(注意不是值傳遞)。對於不可變類型(數值型、字符串、元組),因變量不能修改,因此運算不會影響到變量自身;而對於可變類型(列表字典)來講,函數體運算可能會更改傳入的參數變量。
random.random()生成0-1之間的隨機小數,因此乘以100
精簡代碼,lambda省去了定義函數,map省去了寫for循環過程
UDP、TCP、FTP、HTTP、SMTP等等
一、單引號和雙引號沒有什麼區別,不過單引號不用按shift,打字稍微快一點。表示字符串的時候,單引號裏面能夠用雙引號,而不用轉義字符,反之亦然。
'She said:"Yes." ' or "She said: 'Yes.' "
二、可是若是直接用單引號擴住單引號,則須要轉義,像這樣:
' She said:\'Yes.\' '
三、三引號能夠直接書寫多行,一般用於大段,大篇幅的字符串
"""
hello
world
"""
python垃圾回收主要以引用計數爲主,標記-清除和分代清除爲輔的機制,其中標記-清除和分代回收主要是爲了處理循環引用的難題。
引用計數算法
當有1個變量保存了對象的引用時,此對象的引用計數就會加1
當使用del刪除變量指向的對象時,若是對象的引用計數不爲1,好比3,那麼此時只會讓這個引用計數減1,即變爲2,當再次調用del時,變爲1,若是再調用1次del,此時會真的把對象進行刪除
一、GET請求是經過URL直接請求數據,數據信息能夠在URL中直接看到,好比瀏覽器訪問;而POST請求是放在請求頭中的,咱們是沒法直接看到的;
二、GET提交有數據大小的限制,通常是不超過1024個字節,而這種說法也不徹底準確,HTTP協議並無設定URL字節長度的上限,而是瀏覽器作了些處理,因此長度依據瀏覽器的不一樣有所不一樣;POST請求在HTTP協議中也沒有作說明,通常來講是沒有設置限制的,可是實際上瀏覽器也有默認值。整體來講,少許的數據使用GET,大量的數據使用POST。
三、GET請求由於數據參數是暴露在URL中的,因此安全性比較低,好比密碼是不能暴露的,就不能使用GET請求;POST請求中,請求參數信息是放在請求頭的,因此安全性較高,能夠使用。在實際中,涉及到登陸操做的時候,儘可能使用HTTPS請求,安全性更好。
應用數據分析庫pandas
進程:
一、操做系統進行資源分配和調度的基本單位,多個進程之間相互獨立
二、穩定性好,若是一個進程崩潰,不影響其餘進程,可是進程消耗資源大,開啓的進程數量有限制
線程:
一、CPU進行資源分配和調度的基本單位,線程是進程的一部分,是比進程更小的能獨立運行的基本單位,一個進程下的多個線程能夠共享該進程的全部資源
二、若是IO操做密集,則能夠多線程運行效率高,缺點是若是一個線程崩潰,都會形成進程的崩潰
應用:
IO密集的用多線程,在用戶輸入,sleep 時候,能夠切換到其餘線程執行,減小等待的時間
CPU密集的用多進程,由於假如IO操做少,用多線程的話,由於線程共享一個全局解釋器鎖,當前運行的線程會霸佔GIL,其餘線程沒有GIL,就不能充分利用多核CPU的優點