原創:用python把鏈接指向的網頁直接生成圖片的http服務及網站(含源碼及思想)


原創:用python把鏈接指向的網頁直接生成圖片的http服務及網站(含源碼及思想)


總體思想:
    希望讓調用方通過 http調用傳入一個需要生成圖片的網頁鏈接生成一個網頁的圖片並返回圖片鏈接
    最終調用方式比如:http://127.0.0.1:8888/cgi-bin/test.py?url=http://www.csdn.net/
    上述范例打開之后返回的是 http://www.csdn.net/ 這個網頁最終生成的圖片的鏈接
    這么做的目的就是讓調用的人幾乎不用動腦,當然實現這個的人也會覺得牛逼哄哄:)


    要實現上述這個思想,分解一下就需要實現以下功能:
    1、需要做一個網站
    2、這個網站還需要能執行 python的腳本也就是說要具備cgi處理功能
    3、需要一個代碼能對給定的網址保存為圖片
    4、我們需要一款簡單又可靠的又能執行python腳本的web server


    通過google.com經過一番對python的簡單了解之后我們發現上述四個目標其實都非常簡單:
    1、python自帶了一個cgi web server啟動方式非常之簡單,基本上只需要小學文化:
       在linux終端或這windows的dos窗口運行: python -m CGIHTTPServer 8888
       就實現了目標1和目標2
    2、測試一下我們的這個web server究竟管用不管用
       在當前目錄下建立一個index.html 輸入it works!
       好了在瀏覽器中輸入:http://127.0.0.1:8888/index.html 
       看到了吧,就這么簡單,僅需小學文化水平:)
    3、建立一個簡單的python腳本程序,讓瀏覽器能夠打開,同時也能接收一個url參數
       比如:http://127.0.0.1:8888/cgi-bin/pycgidemo.py?url=http://www.csdn.net/
       在當前目錄下建立一個目錄cgi-bin 然后在里面建立一個文本文件:pycgidemo.py 輸入:
       #!/usr/bin/env python
       =======================================pycgidemo.py====begin========================
# -*- coding: utf-8 -*-


import os
import io
import time
import JSInjection
from PIL import Image
from selenium import webdriver
import html2image
import uuid


if __name__ == '__main__':
   v = [i for i in os.environ.iteritems()]
   print('env is %s' %(repr(v)))
   qs={k:v for k,v in [l.split('=') for l in os.environ['QUERY_STRING'].split('&')]}
   print('Content-type: text/html\n')
   print('<title>pycgidemo</title>')
   print('Hello World<br/>')
   print(qs['url'])


   quit()
        =======================================pycgidemo.py====end========================
好了,測試一下,在瀏覽器中輸入:http://127.0.0.1:8888/cgi-bin/pycgidemo.py?url=http://www.csdn.net/
瀏覽器上顯示:Hello World 
             http://www.csdn.net/
瀏覽器輸入的地址就是我們的cgi腳本程序,同時還接收了一個參數url=這個后面的就是參數,
可以隨便輸入,輸入什么瀏覽器就顯示什么
看到了吧,就這么簡單,僅需初中文化水平:)
    4、web server有了,cgi腳本也能處理了,網站也有了,下一步就是寫一個程序能將給定的url生成圖片
       這個問題看起來很天方夜譚,其實答案是有的,那就是url能生成圖片肯定需要有一個瀏覽器,
       那么問題來了,a、瀏覽器能被調用嗎 b、瀏覽器能把打開的網頁保存成圖片嗎
       這兩個問題其實不難回答:UC、360瀏覽器、QQ瀏覽器、搜狗瀏覽器這些是什么玩意呢?
          說穿了這些都是垃圾,為什么這么說呢,因為他們連開發瀏覽器的最基本能力都沒有,僅僅是把:
 IE瀏覽器或者google瀏覽器拿過來包裝了一下裝個逼而已,既然如此咱們豈不是照樣可以裝逼:)
 
  答案是yes,既然要裝個逼,看看下面我怎么裝逼的啊:(別害怕,有大師在,你其實具備初中文化水平足以)
       
第一步 配置運行及開發環境:
   1、操作系統:linux或 windows 實際采用的是 centos linux的這一種
   2、python2.x、或python3.x 實際采用的是centos自帶的python2.7


第二步 編譯:phantomjs (這是一個開源的能自動化控制的瀏覽器)
sudo yum install gcc gcc-c++ make git openssl-devel freetype-devel fontconfig-devel 
git clone git://github.com/ariya/phantomjs.git 
cd phantomjs 
git checkout 1.9 
./build.sh 
第三步 安裝python相關庫
pip install selenium (這個庫強大,能操縱各種瀏覽器包括:phantomjs、google、firefox等)
pip install pillow
第四步 配置 phantomjs
vi /etc/profile
添加:
export PHANTOMJS_HOME=/soft/phantomjs
PATH=$PATH:$PHANTOMJS_HOME/bin


:wq #保存
source /etc/profile #生效


第五步 寫一個腳本來把url打開並保存為圖像:
這里我寫了兩個簡單的python腳本
1、html2image.py  這個腳本的作用就是打開url然后保存為圖片
2、JSInjection.py 這個腳本的作用是考慮到某些網頁比較長,
       而且內容不滾動到那里就不顯示,那么我就用這個讓它自動滾動到底
3、測試及調用方式很簡單:
   urltoimage = html2image("http://www.csdn.net/", JSInjection.Scroll2Bottom(), '/soft/cgi-bin/aaa.jpg')
   urltoimage.save_image()
   執行這兩行代碼之后就會將  http://www.csdn.net的首頁自動保存為aaa.jpg並保存到 /soft 目錄下
   簡單不,這里僅需小學文化水平:)
4、下面來看看咱們這兩個腳本的代碼哈:
=======================================html2image.py====begin========================
# -*- coding: utf-8 -*-


import io
import time
import JSInjection
from PIL import Image
from selenium import webdriver


__author__ = '黃智(小白救星)'
__version__ = 1.0




class html2image:
    def __init__(self, url, jscode, mfilename):
        #service_log_path = '/soft/chromedriver/chromedriver.log'
        #service_args = ['--verbose', '--no-sandbox']
        
        #driver = webdriver.Chrome('/soft/chromedriver/bin/chromedriver', service_args=service_args, service_log_path=service_log_path) 
        #driver.get('http://www.baidu.com/')
        #driver.quit()
        
        #print('finished')


        #chrome_options = webdriver.ChromeOptions()
        #chrome_options.add_argument('--no-sandbox')
        #self.browser = webdriver.Chrome('/soft/chromedriver', chrome_options=chrome_options)


        #opts = webdriver.ChromeOptions()
        #opts.executable_path="/soft/chromedriver/bin"
        #opts.binary_location="/soft/chromedriver/bin/chromedriver"
        #opts.add_experimental_option("excludeSwitches", ["ignore-certificate-errors"])
        #opts.service_log_path = '/soft/chromedriver/chromedriver.log'
        #opts.add_argument('--no-sandbox')
        #opts.service_args = ['--verbose', '--no-sandbox']
        #self.browser = webdriver.Chrome('/soft/html2image/html2image/cgi-bin/chromedriver', service_args = service_args,service_log_path = service_log_path)
        #self.browser = webdriver.Chrome('/soft/chromedriver/bin/chromedriver', chrome_options=opts)
        #self.browser = webdriver.Chrome(chrome_options=opts)


        #self.browser = webdriver.Chrome(executable_path='/soft/html2image/html2image')
        #self.browser = webdriver.Chrome(executable_path='/soft/chromedriver64',
        #                                service_log_path=r"/soft/html2image/html2image/wlog.log")
        self.browser = webdriver.PhantomJS(service_log_path=r"/soft/html2image/html2image/wlog.log")
        self.browser.set_window_size(1200, 900)
        self.browser.get(url)
        self.jscode = jscode
        self.image = None
        self.filename = mfilename


    def get_image(self):
        if self.jscode is not None and isinstance(self.jscode, JSInjection.JSCode) and self.jscode.get_jscode != "":
            # print(self.jsCode.getJSCode())
            self.browser.execute_script(self.jscode.get_jscode())
            #for i in range(30):
            #    # print(self.browser.title)
            #    if self.jscode.finished_sign in self.browser.title:
            #        break
            #    time.sleep(10)


        self.image = self.browser.get_screenshot_as_png()
        # self.browser.close()
        return self.image


    def get_element_image(self, css_selector):
        if self.image is None:
            self.get_image()
        element = self.browser.find_element_by_css_selector(css_selector)
        left, top = element.location['x'], element.location['y']
        right = left + element.size['width']
        bottom = top + element.size['height']
        im = Image.open(io.BytesIO(self.image))
        im = im.crop((left, top, right, bottom))
        # im.show()
        img_byte_arr = io.BytesIO()
        im.save(img_byte_arr, format='JPEG')
        return img_byte_arr.getvalue()


    def save_image(self, image=None):
        if image is None:
            if self.image is None:
                image = self.get_image()
            else:
                image = self.image
        try:
            with open(self.filename, 'wb') as f:
                f.write(image)
        except IOError:
            return False
        finally:
            del image
        return True


    def __del__(self):
        self.browser.close()
=======================================html2image.py====end==========================


=======================================JSInjection.py====begin=======================
#!/usr/bin/env python3
# -*- coding: utf-8 -*-


"""This is a JavaScript injection model."""
from abc import abstractmethod, ABCMeta


__author__ = '黃智(小白救星)'
__version__ = 1.0




class JSCode:
    __metaclass__ = ABCMeta


    finished_sign = "Hi, I completed the JS injection!"
    # 請在js代碼表示執行完畢的位置加入`finished_code`,外部函數會根據網頁title中是否包含`finished_sign`來判斷js代碼是否執行完畢
    # js函數運行是異步的方式, 若js代碼里有函數執行,直接把`finished_code`加到最后是行不通的
    # 雖然有方法可以把函數改成同步方式,但沒想到通式的方法(js盲),只能做這樣處理了.
    finished_code = "document.title += '" + finished_sign + "';"


    @abstractmethod
    def get_jscode(self):
        return ""




class Scroll2Bottom(JSCode):
    def get_jscode(self):
        return """(function () {
            var y = 0;
            var step = 100;
            var height = document.body.scrollHeight;
            function f() {
                //if (y < document.body.scrollHeight) {//這種情況下, 若html下拉會觸發加載更多,會陷入循環內,直到加載完所有數據或函數運行時間超時
                if (y < height) { //這種情況下, 還是會觸發加載更多, 但不會陷入循環中, 得到的圖片可以進行裁剪, 或者根據屏幕分辨率事先算好觸發加載更多的邊界條件
                    y += step;
                    //window.document.body.scrollTop = y;
                    window.scrollTo(0, y);
                    setTimeout(f, 100);
                } else {
                    window.scrollTo(0, 0);""" + self.finished_code + """
                }
            }
            setTimeout(f, 1000);
        })();"""
=======================================JSInjection.py====end=========================


第六步 改造一下我們之前寫的 pycgidemo.py讓他來調用 我們上面的圖片生成及保存代碼
這里暫時新建一個文件,放在 cgi-bin目錄下,就叫 test.py吧或者叫做test.cgi也可以
=======================================test.py====begin=========================
#!/usr/bin/env python
# -*- coding: utf-8 -*-


import os
import io
import time
import JSInjection
from PIL import Image
from selenium import webdriver
import html2image
import uuid


if __name__ == '__main__':
    v = [i for i in os.environ.iteritems()]
    print('env is %s' %(repr(v)))
    qs={k:v for k,v in [l.split('=') for l in os.environ['QUERY_STRING'].split('&')]}
    print('Content-type: text/html\n')
    print('<title>urlsavetoimage</title>')
    u=str(uuid.uuid1())
    filename = '/soft/'+u+'.jpg'
    h2i = html2image.html2image(qs['url'], JSInjection.Scroll2Bottom(), filename)
    h2i.save_image()
    print('<a href="'+'/'+u+'.jpg'+'" target=_blank>'+'/'+u+'.jpg'+'</a>')
    quit()
=======================================test.py====end==========================


第七步 打開瀏覽器輸入:http://127.0.0.1:8888/cgi-bin/test.py?url=http://www.csdn.net/
url后面的鏈接可以隨意修改,這個過程稍微有點慢,大概需要機秒鍾時間,
當然了這是因為java、python、PHP、C# 這些腳本語言本身就是這么垃圾,沒辦法啊,
想快的話參考我這個小工具:
    http://blog.csdn.net/tengyunjiawu_com/article/details/76228675
    鏈接對應的網頁保存為圖片,用時:瞬間,適合任何網頁,這個純編譯型語言開發的哦


第八步:處理中文亂碼問題
yum install bitmap-fonts bitmap-fonts-cjk


大功告成!整個過程僅需中小學文化程度:)

寫程序其實很簡單,本人精通,sorry,是熟練:)掌握C、C++、Java、PHP、Python、Delphi、C# 等數十種編程語言,從來沒覺得有啥牛逼之處,

寫代碼關鍵還是思想:思考問題、分析分解問題才是關鍵,工具沒有高低之分,只有思想境界的差距:)

本人原創,未經許可可隨意轉載!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM