原创:用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# 等数十种编程语言,从来没觉得有啥牛逼之处,

写代码关键还是思想:思考问题、分析分解问题才是关键,工具没有高低之分,只有思想境界的差距:)

本人原创,未经许可可随意转载!

原创:用python把链接指向的网页直接生成图片的http服务及网站(含源码及思想)的更多相关文章

  1. 没有内涵段子可以刷了,利用Python爬取段友之家贴吧图片和小视频(含源码)

    由于最新的视频整顿风波,内涵段子APP被迫关闭,广大段友无家可归,但是最近发现了一个"段友"的app,版本更新也挺快,正在号召广大段友回家,如下图,有兴趣的可以下载看看(ps:我不 ...

  2. 微信公众平台开发-OAuth2.0网页授权(含源码)

    微信公众平台开发-OAuth2.0网页授权接口.网页授权接口详解(含源码)作者: 孟祥磊-<微信公众平台开发实例教程> 在微信开发的高级应用中,几乎都会使用到该接口,因为通过该接口,可以获 ...

  3. Python 基于python实现的http接口自动化测试框架(含源码)

    基于python实现的http+json协议接口自动化测试框架(含源码) by:授客 QQ:1033553122      欢迎加入软件性能测试交流 QQ群:7156436  由于篇幅问题,采用百度网 ...

  4. HTML5网页录音和压缩,边猜边做..(附源码)

    宣传一下自己的qq群: (暗号:C#交流) 欢迎喜欢C#,热爱C#,正在学习C#,准备学习C#的朋友来这里互相学习交流,共同进步 群刚建,人不多,但是都是真正热爱C#的 我也是热爱C#的 希望大家可以 ...

  5. 零基础自学Python十天,写了一款猜数字小游戏,附源码和软件下载链接!

    自学一门语言最重要的是要及时给自己反馈,那么经常写一些小程序培养语感很重要,写完可以总结一下程序中运用到了哪些零散的知识点. 本程序中运用到的知识点有: 1.输入输出函数 (input.print) ...

  6. python下的orm基本操作(1)--Mysql下的CRUD简单操作(含源码DEMO)

    最近逐渐打算将工作的环境转移到ubuntu下,突然发现对于我来说,这ubuntu对于我这种上上网,收收邮件,写写博客,写写程序的时实在是太合适了,除了刚接触的时候会不怎么完全适应命令行及各种权限管理, ...

  7. 腾讯QQ音乐网页版 音频初始化模块解压混淆js源码

    define("js/view/playerBar.js",function(t,e,o){ var i = t("js/lib/zepto.js"), a = ...

  8. Python实战:截图识别文字,过万使用量版本!(附源码!!)

    前人栽树后人乘凉,以不造轮子为由 使用百度的图片识字功能,实现了一个上万次使用量的脚本. 系统:win10 Python版本:python3.8.6 pycharm版本:pycharm 2021.1. ...

  9. Java+JQuery实现网页显示本地文件目录(含源码)

    原文地址:http://www.cnblogs.com/liaoyu/p/uudisk.html 源码地址:https://github.com/liaoyu/uudisk 前段时间为是练习JQuer ...

随机推荐

  1. opencv知识积累

    1.OpenCV 3计算机视觉:Python语言实现 https://github.com/techfort/pycv 2.OpenCV3编程入门 opencv 均值模糊:一般用来处理图像的随机噪声 ...

  2. IntelliJ IDEA 2017版 spring-boot2.0.4的yml配置使用

    一.必须配置字端两个 server: port: 8080 servlet: context-path: /demo 二.两种mvc转换springboot,一种是注解,一种就是.yml或proper ...

  3. silverlight 定时器 System.Windows.Threading.DispatcherTimer

    声明 System.Windows.Threading.DispatcherTimer _MessageControler; //刷新 _MessageControler = new System.W ...

  4. 敏捷项目管理工具-Trello(电子看板)

    Trello简介(https://www.trello.com) A Trello board is a list of lists, filled with cards, used by you a ...

  5. java基础-day30

    第07天 MySQL数据库 今日内容介绍 u 多表关系实战练习 u 多表查询 u SQL语句的练习 第1章   多表关系实战练习 1.1  多表关系--实战1--省和市 1.1.1 需求分析 在数据库 ...

  6. 网络timeout区分

    ConnectTimeout 连接建立时间,三次握手完成时间 SocketTimeout 数据传输过程中数据包之间间隔的最大时间 下面重点说下SocketTimeout,比如有如下图所示的http请求 ...

  7. 第85讲:Scala中For表达式的强大表现力实战

    今天来学一下scala中的For表达式的用法. package scala.learn case class Persons(name:String,isMale:Boolean,children:P ...

  8. hdu 2191 【背包问题】

    题目 请输出能够购买大米的最多重量,注意是重量不是价值. 把每一种物品拧出来,用01背包解决. #include <cstdio> #include <iostream> #i ...

  9. NoSQL数据库的分布式算法

    本文译自 Distributed Algorithms in NoSQL Databases 系统的可扩展性是推动NoSQL运动发展的的主要理由,包含了分布式系统协调,故障转移,资源管理和许多其他特性 ...

  10. ElementTriArgyris

    class ElementTriArgyris(ElementH2): nodal_dofs = 6 facet_dofs = 1 dim = 2 maxdeg = 5 def gdof(self, ...