爬蟲的基本原理
一、爬蟲的基本原理
網絡爬蟲的價值其實就是數據的價值,在互聯網社會中,數據是無價之寶,一切皆為數據,誰擁有了大量有用的數據,誰就擁有了決策的主動權。
爬蟲聚合站點
//qbt4.mobduos.com/promote/pc/?code=339115928&utm=339115928
//www.hrdatayun.com
//tophub.today/c/tech
//www.vlogxz.com/
1.0 爬蟲定義
簡單來講,爬蟲就是一個探測機器,它的基本操作就是模擬人的行為去各個網站溜達,點點按鈕,查查數據,或者把看到的信息背回來。就像一隻蟲子在一幢樓里不知疲倦地爬來爬去。
1.1 爬蟲薪資
1.2 爬蟲前景
每個職業都是有一個橫向和縱向的發展,也就是所謂的廣度和深度的意思。第一、如果專研得夠深,你的爬蟲功能很強大,性能很高,擴展性很好等等,那麼還是很有前途的。第二、爬蟲作為數據的來源,後面還有很多方向可以發展,比如可以往大數據分析、數據展示、機器學習等方面發展,前途不可限量,現在作為大數據時代,你佔據在數據的的入口,還怕找不到發展方向嗎?
1.3 爬蟲創業
案列:
1.1.1 獲取網頁
爬蟲首先要做的工作就是獲取網頁,這裡就是獲取網頁的源代碼。源代碼里包含了網頁的部分有用信息,所以只要把源代碼獲取下來,就可以從中提取想要的信息了。
- 使用socket下載一個頁面
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:chenshifeng
@file:00.py
@time:2022/10/14
"""
import socket
# 不需要安裝
# 訪問網站
url = 'www.baidu.com'
# 端口
port = 80
def blocking():
sock = socket.socket() # 建立對象
sock.connect((url, port)) # 連接網站 ,發出一個HTTP請求
request_url = 'GET / HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n'
sock.send(request_url.encode()) # 根據請求頭來發送請求信息
response = b'' # 建立一個二進制對象用來存儲我們得到的數據
chunk = sock.recv(1024) # 每次獲得的數據不超過1024位元組
while chunk: # 循環接收數據,因為一次接收不完整
response += chunk
chunk = sock.recv(1024)
header, html = response.split(b'\r\n\r\n', 1)
f = open('index.html', 'wb')
f.write(html)
f.close()
if __name__ == '__main__':
blocking()
1.1.2 提取信息
獲取網頁源代碼後,接下來就是分析網頁源代碼,從中提取我們想要的數據。首先,最通用的方法便是採用正則表達式提取,這是一個萬能的方法,但是在構造正則表達式時比較複雜且容易出錯。
另外,由於網頁的結構有一定的規則,所以還有一些根據網頁節點屬性、CSS 選擇器或 XPath 來提取網頁信息的庫,如 Beautiful Soup、pyquery、lxml 等。使用這些庫,我們可以高效快速地從中提取網頁信息,如節點的屬性、文本值等。
提取信息是爬蟲非常重要的部分,它可以使雜亂的數據變得條理清晰,以便我們後續處理和分析數據。
1.1.3 保存數據
提取信息後,我們一般會將提取到的數據保存到某處以便後續使用。這裡保存形式有多種多樣,如可以簡單保存為 TXT 文本或 JSON 文本,也可以保存到數據庫,如 MySQL 和 MongoDB 等,也可保存至遠程服務器,如藉助 SFTP 進行操作等。
1.1.4 自動化程序
說到自動化程序,意思是說爬蟲可以代替人來完成這些操作。首先,我們手工當然可以提取這些信息,但是當量特別大或者想快速獲取大量數據的話,肯定還是要藉助程序。爬蟲就是代替我們來完成這份爬取工作的自動化程序,它可以在抓取過程中進行各種異常處理、錯誤重試等操作,確保爬取持續高效地運行。
二、HTTP基本原理
2.1.1 URI 和 URL
這裡我們先了解一下 URI 和 URL,URI 的全稱為 Uniform Resource Identifier,即統一資源標誌符,URL 的全稱為 Universal Resource Locator,即統一資源定位符。
什麼是URL?
Uniform Resource Locator或者簡稱URL— 顧名思義 — 就是對於某種web資源的引用,並且包含了如何獲取該資源的方式。 最常見到的場景就是指一個網站的地址,也就是你在瀏覽器地址欄見到的那個東西。
一個URL由如下幾個部分構成:
//img.vm.laomishuo.com/image/2019/10/F9A91867-194B-4F18-90CF-65CE2A8BFDDA.jpeg
- 協議: 通常是https或者http。表示通過何種方式獲取該資源。你可能還見過其他協議類型,比如ftp或者file,協議後面跟着://
- 主機名: 可以是一個已經在DNS服務器註冊過的域名 —— 或者是一個IP地址 —— 域名就表示背後的IP地址。一組主要由數字組成的用於標識接入網絡的設備的字符串。
主機名後面可以指定端口,端口是可選的,如果不指定則使用默認端口,端口和主機名之間通過冒號隔開。 - 資源路徑: 用於表示資源在主機上的文件系統路徑。
可以在這之後通過問號連接可選的查詢參數,如果有多個查詢參數,通過&符連接
最後一項,如果需要的話可以添加#作為需要跳轉的頁面上的矛點名稱。
一個URL的組成部分可以參考下面的圖示:
什麼是URI?
接下來我們來了解一下究竟什麼是URI。與URL相似的部分是,Uniform Resource Identifier同樣定義了資源的標識。但不同點在於URI通常不會包含獲取資源的方式。
ISBN作為書目的資源定義就是一種URI,但不是URL。它清楚地為每一種出版的書目定義了唯一的數字編號,但沒有包含任何如何獲取這種資源的方法。
URI代表着統一資源標識符(UniformResourceIdentifier),用於標識某一互聯網資源名稱。 該種標識允許用戶對任何包括本地和互聯網的資源通過特定的協議進行交互操作。比如上面URL中的F9A91867-194B-4F18-90CF-65CE2A8BFDDA.jpeg。
URL 和 URI 的區別:
(1)URL:Uniform Resource Locator統一資源定位符;
(2)URI: Uniform Resource Identifier統一資源標識符;
因此我們可以這樣總結:URI是URL的超集,URL是URI的子集。每一個URL都必定也是一個URI。
其實一直有個誤解,很多人以為URI是URL的子集,其實應該反過來。URL是URI的子集才對。簡單解釋下。
假設”小白”(URI)是一種資源,而”在迪麗亦巴的懷裡”表明了一個位置。如果你想要找到(locate)小白,那麼你可以到”在迪麗亦巴懷裡”找到小白,而”在迪麗亦巴懷裡的/小白”才是我們常說的URL。而”在迪麗亦巴懷裡的/小白”(URL)顯然是”小白”(URI)的子集,畢竟,”小白”還可能是”在牛亦菲懷裡的/小白”(其他URL)。
所以實際上URL就是一種特定的URI,這種URI還含有如何獲取資源的信息。如果一定需要一句話來總結本文的主要內容,那麼RFC3986中的這句定義一定是最合適的:
The term 「Uniform Resource Locator」 (URL) refers to the subset of URIs that, in addition to identifying a resource, provide a means of locating the resource by describing its primary access mechanism.
2.1.2 超文本
其英文名稱叫作 hypertext,我們在瀏覽器里看到的網頁就是超文本解析而成的,其網頁源代碼是一系列 HTML 代碼,裏面包含了一系列標籤,比如 img 顯示圖片,p 指定顯示段落等。瀏覽器解析這些標籤後,便形成了我們平常看到的網頁,而網頁的源代碼 HTML 就可以稱作超文本。
2.1.3 HTTP 和 HTTPS
在百度的首頁 //www.baidu.com/ 中,URL 的開頭會有 http 或 https,這個就是訪問資源需要的協議類型,有時我們還會看到 ftp、sftp、smb 開頭的 URL,那麼這裡的 ftp、sftp、smb 都是指的協議類型。在爬蟲中,我們抓取的頁面通常就是 http 或 https 協議的,我們在這裡首先來了解一下這兩個協議的含義。
- HTTP 的全稱是 Hyper Text Transfer Protocol,中文名叫做超文本傳輸協議
- HTTPS 的全稱是 Hyper Text Transfer Protocol over Secure Socket Layer,是以安全為目標的 HTTP 通道,簡單講是 HTTP 的安全版,即 HTTP 下加入 SSL 層,簡稱為 HTTPS。
參考://baike.baidu.com/item/HTTPS/285356?fr=aladdin
2.1.4 HTTP 請求過程
我們在瀏覽器中輸入一個 URL,回車之後便會在瀏覽器中觀察到頁面內容。實際上,這個過程是瀏覽器向網站所在的服務器發送了一個請求,網站服務器接收到這個請求後進行處理和解析,然後返回對應的響應,接着傳回給瀏覽器。響應里包含了頁面的源代碼等內容,瀏覽器再對其進行解析,便將網頁呈現了出來,模型如圖 所示。
2.1.5 請求
請求,由客戶端向服務端發出,可以分為 4 部分內容:請求方法(Request Method)、請求的網址(Request URL)、請求頭(Request Headers)、請求體(Request Body)。
面板組成
-
請求方法
表 1-1 其他請求方法
方 法 描 述 GET 請求頁面,並返回頁面內容 HEAD 類似於 GET 請求,只不過返回的響應中沒有具體的內容,用於獲取報頭 POST 大多用於提交表單或上傳文件,數據包含在請求體中 PUT 從客戶端向服務器傳送的數據取代指定文檔中的內容 DELETE 請求服務器刪除指定的頁面 CONNECT 把服務器當作跳板,讓服務器代替客戶端訪問其他網頁 OPTIONS 允許客戶端查看服務器的性能 TRACE 回顯服務器收到的請求,主要用於測試或診斷
本表參考://www.runoob.com/http/http-methods.html。
-
請求的網址
請求的網址,即統一資源定位符 URL,它可以唯一確定我們想請求的資源。
-
請求頭
參考://byvoid.com/zhs/blog/http-keep-alive-header/
- Accept
- Accept-Language
- Accept-Encoding
- Host 主機
- Cookie 會話信息 身份
- Referer 記錄來源
- User-Agent 瀏覽器得指紋信息
- Content-Type 類型
-
請求體
請求體一般承載的內容是 POST 請求中的表單數據,而對於 GET 請求,請求體則為空。
2.1.6 響應
響應,由服務端返回給客戶端,可以分為三部分:響應狀態碼(Response Status Code)、響應頭(Response Headers)和響應體(Response Body)。
- 響應狀態碼
響應狀態碼錶示服務器的響應狀態,如 200 代表服務器正常響應,404 代表頁面未找到,500 代表服務器內部發生錯誤。在爬蟲中,我們可以根據狀態碼來判斷服務器響應狀態,如狀態碼為 200,則證明成功返回數據,再進行進一步的處理,否則直接忽略。表 2-3 列出了常見的錯誤代碼及錯誤原因。
1.1常見的錯誤代碼及錯誤原因
狀態碼 | 說 明 | 詳 情 |
---|---|---|
100 | 繼續 | 請求者應當繼續提出請求。服務器已收到請求的一部分,正在等待其餘部分 |
101 | 切換協議 | 請求者已要求服務器切換協議,服務器已確認並準備切換 |
200 | 成功 | 服務器已成功處理了請求 |
201 | 已創建 | 請求成功並且服務器創建了新的資源 |
202 | 已接受 | 服務器已接受請求,但尚未處理 |
203 | 非授權信息 | 服務器已成功處理了請求,但返回的信息可能來自另一個源 |
204 | 無內容 | 服務器成功處理了請求,但沒有返回任何內容 |
205 | 重置內容 | 服務器成功處理了請求,內容被重置 |
206 | 部分內容 | 服務器成功處理了部分請求 |
300 | 多種選擇 | 針對請求,服務器可執行多種操作 |
301 | 永久移動 | 請求的網頁已永久移動到新位置,即永久重定向 |
302 | 臨時移動 | 請求的網頁暫時跳轉到其他頁面,即暫時重定向 |
303 | 查看其他位置 | 如果原來的請求是 POST,重定向目標文檔應該通過 GET 提取 |
304 | 未修改 | 此次請求返回的網頁未修改,繼續使用上次的資源 |
305 | 使用代理 | 請求者應該使用代理訪問該網頁 |
307 | 臨時重定向 | 請求的資源臨時從其他位置響應 |
400 | 錯誤請求 | 服務器無法解析該請求 |
401 | 未授權 | 請求沒有進行身份驗證或驗證未通過 |
403 | 禁止訪問 | 服務器拒絕此請求 |
404 | 未找到 | 服務器找不到請求的網頁 |
405 | 方法禁用 | 服務器禁用了請求中指定的方法 |
406 | 不接受 | 無法使用請求的內容響應請求的網頁 |
407 | 需要代理授權 | 請求者需要使用代理授權 |
408 | 請求超時 | 服務器請求超時 |
409 | 衝突 | 服務器在完成請求時發生衝突 |
410 | 已刪除 | 請求的資源已永久刪除 |
411 | 需要有效長度 | 服務器不接受不含有效內容長度標頭字段的請求 |
412 | 未滿足前提條件 | 服務器未滿足請求者在請求中設置的其中一個前提條件 |
413 | 請求實體過大 | 請求實體過大,超出服務器的處理能力 |
414 | 請求 URI 過長 | 請求網址過長,服務器無法處理 |
415 | 不支持類型 | 請求格式不被請求頁面支持 |
416 | 請求範圍不符 | 頁面無法提供請求的範圍 |
417 | 未滿足期望值 | 服務器未滿足期望請求標頭字段的要求 |
500 | 服務器內部錯誤 | 服務器遇到錯誤,無法完成請求 |
501 | 未實現 | 服務器不具備完成請求的功能 |
502 | 錯誤網關 | 服務器作為網關或代理,從上游服務器收到無效響應 |
503 | 服務不可用 | 服務器目前無法使用 |
504 | 網關超時 | 服務器作為網關或代理,但是沒有及時從上游服務器收到請求 |
505 | HTTP 版本不支持 | 服務器不支持請求中所用的 HTTP 協議版本 |
- 響應頭
響應頭包含了服務器對請求的應答信息,如 Content-Type、Server、Set-Cookie 等。下面簡要說明一些常用的頭信息。
- Date:標識響應產生的時間。
- Last-Modified:指定資源的最後修改時間。
- Content-Encoding:指定響應內容的編碼。
- Server:包含服務器的信息,比如名稱、版本號等。
- Content-Type:文檔類型,指定返回的數據類型是什麼,如 text/html 代表返回 HTML 文檔,application/x-javascript 則代表返回 JavaScript 文件,image/jpeg 則代表返回圖片。
- Set-Cookie:設置 Cookies。響應頭中的 Set-Cookie 告訴瀏覽器需要將此內容放在 Cookies 中,下次請求攜帶 Cookies 請求。
- Expires:指定響應的過期時間,可以使代理服務器或瀏覽器將加載的內容更新到緩存中。如果再次訪問時,就可以直接從緩存中加載,降低服務器負載,縮短加載時間。
- 響應體
最重要的當屬響應體的內容了。響應的正文數據都在響應體中,比如請求網頁時,它的響應體就是網頁的 HTML 代碼;請求一張圖片時,它的響應體就是圖片的二進制數據。我們做爬蟲請求網頁後,要解析的內容就是響應體,如圖 2-8 所示。
在瀏覽器開發者工具中點擊 Preview,就可以看到網頁的源代碼,也就是響應體的內容,它是解析的目標。
在做爬蟲時,我們主要通過響應體得到網頁的源代碼、JSON 數據等,然後從中做相應內容的提取。
三、web網頁基礎
3.1 網頁的組成
網頁可以分為三大部分 —— HTML、CSS 和 JavaScript。如果把網頁比作一個人的話,HTML 相當於骨架,JavaScript 相當於肌肉,CSS 相當於皮膚,三者結合起來才能形成一個完善的網頁。下面我們分別來介紹一下這三部分的功能。
3.1.1 html
HTML 是用來描述網頁的一種語言。
- HTML 指的是超文本標記語言 (Hyper Text Markup Language)
- HTML 不是一種編程語言,而是一種標記語言 (markup language)
- 標記語言是一套標記標籤 (markup tag)
- HTML 使用標記標籤來描述網頁
HTML 標籤
- HTML 標記標籤通常被稱為 HTML 標籤 (HTML tag)。
- HTML 標籤是由尖括號包圍的關鍵詞,比如
- HTML 標籤通常是成對出現的,比如 和
- 標籤對中的第一個標籤是開始標籤,第二個標籤是結束標籤
- 開始和結束標籤也被稱為開放標籤和閉合標籤
HTML 文檔 = 網頁
- HTML 文檔描述網頁
- HTML 文檔包含 HTML 標籤和純文本
- HTML 文檔也被稱為網頁
Web 瀏覽器的作用是讀取 HTML 文檔,並以網頁的形式顯示出它們。瀏覽器不會顯示 HTML 標籤,而是使用標籤來解釋頁面的內容:
<html>
<body>
<h1>我的第一個標題</h1>
<p>我的第一個段落。</p>
</body>
</html>
3.1.2 css
什麼是 CSS?
- CSS 指層疊樣式表 (Cascading Style Sheets)
- 樣式定義如何顯示 HTML 元素
- 樣式通常存儲在樣式表中
- 把樣式添加到 HTML 4.0 中,是為了解決內容與表現分離的問題
- 外部樣式表可以極大提高工作效率
- 外部樣式表通常存儲在 CSS 文件中
- 多個樣式定義可層疊為一個
body {
background-color:#d0e4fe;
}
h1 {
color:orange;
text-align:center;
}
p {
font-family:"Times New Roman";
font-size:20px;
}
3.1.3 JavaScript
JavaScript 是屬於 HTML 和 Web 的編程語言。
編程令計算機完成您需要它們做的工作。
JavaScript 是 web 開發人員必須學習的 3 門語言中的一門:
- HTML 定義了網頁的內容
- CSS 描述了網頁的布局
- JavaScript 控制了網頁的行為
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<!-- 編寫css文件 需要使用 style -->
<style>
h1{
color: red;
text-align: center;
}
</style>
<body>
<!-- 編寫文本 需要使用 h5 標籤 -->
<h1 id="text">大家好,我是塵世風</h1>
<p>
</p>
<div>
<img src="//t9.baidu.com/it/u=2219788502,4244472931&fm=218&app=137&size=f242,150&n=0&f=JPEG&fmt=auto?s=F9231F703F227A15696CD9CD0300A0B3&sec=1658595600&t=4967a0d0d262421dd9926f00a598186e" alt="">
</div>
<button id="xl">
點擊我切換數據
</button>
<!-- 編寫JS文件 需要使用 script標籤 -->
<script>
document.getElementById('xl').onclick = function () {
document.getElementById("text").innerText = '大家好,我是隔壁老王'
}
</script>
</body>
</html>
四、會話和Cookies
在瀏覽網站的過程中,我們經常會遇到需要登錄的情況,有些頁面只有登錄之後才可以訪問,而且登錄之後可以連續訪問很多次網站,但是有時候過一段時間就需要重新登錄。還有一些網站,在打開瀏覽器時就自動登錄了,而且很長時間都不會失效,這種情況又是為什麼?其實這裏面涉及會話(Session)和 Cookies 的相關知識,本節就來揭開它們的神秘面紗。
4.1.1 無狀態 HTTP
在了解會話和 Cookies 之前,我們還需要了解 HTTP 的一個特點,叫作無狀態。
-
會話
會話,其本來的含義是指有始有終的一系列動作 / 消息。比如,打電話時,從拿起電話撥號到掛斷電話這中間的一系列過程可以稱為一個會話。
-
Cookies
Cookies 指某些網站為了辨別用戶身份、進行會話跟蹤而存儲在用戶本地終端上的數據。
-
Cookies 列表
- Name,即該 Cookie 的名稱。Cookie 一旦創建,名稱便不可更改
- Value,即該 Cookie 的值。如果值為 Unicode 字符,需要為字符編碼。如果值為二進制數據,則需要使用 BASE64 編碼。
- Max Age,即該 Cookie 失效的時間,單位秒,也常和 Expires 一起使用,通過它可以計算出其有效時間。Max Age 如果為正數,則該 Cookie 在 Max Age 秒之後失效。如果為負數,則關閉瀏覽器時 Cookie 即失效,瀏覽器也不會以任何形式保存該 Cookie。
- Path,即該 Cookie 的使用路徑。如果設置為 /path/,則只有路徑為 /path/ 的頁面可以訪問該 Cookie。如果設置為 /,則本域名下的所有頁面都可以訪問該 Cookie。
- Domain,即可以訪問該 Cookie 的域名。例如如果設置為 .zhihu.com,則所有以 zhihu.com,結尾的域名都可以訪問該 Cookie。
- Size 字段,即此 Cookie 的大小。
- Http 字段,即 Cookie 的 httponly 屬性。若此屬性為 true,則只有在 HTTP Headers 中會帶有此 Cookie 的信息,而不能通過 document.cookie 來訪問此 Cookie。
- Secure,即該 Cookie 是否僅被使用安全協議傳輸。安全協議。安全協議有 HTTPS,SSL 等,在網絡上傳輸數據之前先將數據加密。默認為 false
五、socket介紹
什麼是 Socket?
在計算機通信領域,socket 被翻譯為「套接字」,它是計算機之間進行通信的一種約定或一種方式。通過 socket 這種約定,一台計算機可以接收其他計算機的數據,也可以向其他計算機發送數據
應該是應用層與傳輸層間的一個抽象層
參考://www.jianshu.com/p/066d99da7cbd
流程圖
請求報文格式
套接字對象服務端方法
綜合案例—使用socket下載圖片
url = '//img1.baidu.com/it/u=3028486691,1206269421&fm=253&fmt=auto&app=138&f=JPEG?w=499&h=323'
import socket # socket模塊是python自帶的內置模塊,不需要我們去下載
# 創建套接字客戶端
client = socket.socket()
# 訪問網站
url = 'img1.baidu.com'
# 端口
port = 80
# 連接,通過(ip,端口)來進行連接
client.connect((url,port))
resq = "GET /it/u=3028486691,1206269421&fm=253&fmt=auto&app=138&f=JPEG?w=499&h=323 HTTP/1.0\r\nHost: img1.baidu.com\r\n\r\n"
# 根據請求頭來發送請求信息
client.send(resq.encode())
# 建立一個二進制對象用來存儲我們得到的數據
result = b''
data = client.recv(1024)
# 循環接收響應數據 添加到bytes類型
while data:
result+=data
data = client.recv(1024)
import re
# re.S 匹配包括換行在內的所有字符 ,去掉響應頭
images = re.findall(b'\r\n\r\n(.*)',result, re.S)
# 打開一個文件,將我們讀取到的數據存入進去,即下載到本地我們獲取到的圖片
with open("可愛的小姐姐.jpg","wb") as f:
f.write(images[0])
六、httpx模塊
httpx是Python新一代的網絡請求庫,它包含以下特點
- 基於Python3的功能齊全的http請求模塊
- 既能發送同步請求,也能發送異步請求
- 支持HTTP/1.1和HTTP/2
- 能夠直接向WSGI應用程序或者ASGI應用程序發送請求
環境安裝
pip install httpx
測試
headers = {'user-agent': 'my-app/1.0.0'}
params = {'key1': 'value1', 'key2': 'value2'}
url = '//httpbin.org/get'
r = httpx.get(url, headers=headers, params=params)
爬蟲請求案例
# encoding: utf-8
"""
@author:chenshifeng
@file: 爬蟲案例.py
@time:2022/10/14
"""
import httpx
import os
class S_wm(object):
def __init__(self):
self.headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
}
def get_url_list(self):
url_list = ['//img1.baidu.com/it/u=1875739781,4152007440&fm=253&fmt=auto&app=120&f=JPEG?w=1024&h=576',
'//img1.baidu.com/it/u=3980896846,3728494487&fm=253&fmt=auto&app=138&f=JPEG?w=333&h=499',
'//img1.baidu.com/it/u=467548803,2897629727&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500',
]
return url_list
def save_image(self,filename,img):
with open(filename, 'wb') as f:
f.write(img.content)
print('圖片提取成功')
def run(self):
url_list = self.get_url_list()
for index,u in enumerate(url_list):
file_name = './image/{}.jpg'.format(index)
data = httpx.request('get', u, headers=self.headers)
self.save_image(file_name,data)
if __name__ == '__main__':
url = '//www.vmgirls.com/13344.html'
s = S_wm()
if os.path.exists("./image") is False:
os.mkdir('./image')
s.run()