整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          牛逼!40行Python代碼把html網頁保存為pdf,太方便了

          近臨近開學了,大家都在忙著準備各種學習的資料,準備在新的學期好好學習,充實自己。小編身邊的同學也是如此,最近,小編的同學小麗就遇到了一個很棘手的問題。

          她想將一個網頁的Python學習的教程打印下來,方便自己來學習,但是上千頁的教程,如果通過手動的方式,一個一個的去轉成pdf并保存到本地,實在是麻煩的不。

          這就是一個html轉pdf的問題,其實網上有很多不錯的html資源,但是苦于學習起來,不方便!于是小編就跟小麗保證,這點小事包在我身上。今天,小編就跟分享一下如何用Python把html資料變成pdf。

          01.抓取的學習資料

          如今網上的在線學習資料可謂是多如牛毛,為了方便講解,小編就利用python3.9.2的中文文檔作為演示的例子,來將其抓取并保存到本地,其網頁鏈接如下:

          https://docs.python.org/zh-cn/3.9/tutorial/index.html

          打開上述鏈接后,大家會在網頁中找到不同內容的鏈接地址,包括了基礎的python字符、python語法等內容。

          02.獲取網頁鏈接

          在上圖中,我們需要格外關注的是紅色方格標注的鏈接,每個鏈接都會跳轉到對應的子網頁中,而在子網頁中,就是我們想要保存的內容。

          可以看到,上圖中,在python速覽子頁面中,包含了我們需要提取的文字內容。所以將html內容保存為pdf的第一步便是獲取到子頁面的鏈接。由于教程大都是固定內容,因此對于教程的網頁,大都采用的是靜態頁面,在網頁源代碼中可以很輕松地找到子頁面的網頁鏈接。

          對于子網頁的鏈接抓取,程序如下圖所示:

          程序中,通過BeautifulSoup庫來解析網頁源代碼,然后提取所有的子頁面鏈接地址并返回,如果抓取失敗,則直接返回None


          03.html轉pdf

          在得到子網頁的鏈接后,接下來就是將html的子網頁保存為pdf文件。小編使用的pdfkit庫,pdfkit庫可以將網頁保存為pdf文檔。首先小編來介紹一下pdfkit庫的安裝。

          • 下載https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox-0.12.6-1.mxe-cross-win64.7z 并解壓到本地文件中。(后臺輸入:pdf) 直接獲取。
          • 將解壓文件中的bin文件路徑添加到系統變量Path中。
          • 執行pip install pdfkit
          • 執行pip install wkhtmltopdf

          按照上述的操作流程,就可以安裝pdfkit庫。對于pdfkit庫的使用,常見的用法有以下三種:

          上面的程序主要完成以下幾步:

          首先需要指定wkhtmltopdf.exe文件的路徑;

          • 然后分別通過from_url、from_file和from_string的三種方式來保存為pdf文件;
          • 需要注意的是,from_file和from_url中的第一個參數必須是一個html的字符串或者是html文檔的列表;
          • 但是小編通過程序運行發現,from_url第一個參數只能是html的字符串,不能是html的列表


          因此,pdfkit庫只能將子網頁保存為單獨的pdf文檔,無法直接通過pdfkit庫將所有的子網頁拼接成一個完整的pdf文檔,小編通過PyPDF2庫中的PdfFileMerger類來實現pdf文檔的拼接。程序如下圖所示。

          程序中首先將所有的html網頁保存為單獨的pdf文檔,然后通過PdfFileMerger類對象來實現pdf文檔的拼接。最后就可以得到全部的pdf內容。最后我們通過視頻的展示,來看一下程序的效果吧。


          除此之外,程序不光可以抓取python3.9的中文文檔,針對其他的在線文檔,只需要對獲取網頁鏈接的程序進行修改即可抓取,例如對于Flask中文文檔的抓取,程序只需要按照下圖進行修改,即可將Flask的在線文檔保存為PDF文檔。

          04.總結

          學習Python其實非常有趣,也很有用。因為Python有大量的現成的庫,可以幫助我們把工作中的很多瑣碎的煩事輕松解決。小編將上述的程序稍加修改,很快就幫阿麗搞定了教程,保存為pdf發送給了她,小編與女神的關系更拉近了一步

          請耐心慢慢刷新到頁面完整顯示出來

          https://fjxasdf.github.io/daogou/

          原文章https://www.toutiao.com/i6711294610594857476/

          哪些優化?

          1.顯示商品圖片

          2.沒有顯示全部商品,只顯示熱門商品,避免數據、圖片加載太慢

          3.樣式稍微美化了

          4.上傳到GitHub,不過GitHub很卡,要刷新等好久才能看到

          python讀取excel生成json代碼

          import xlrd
          from datetime import date,datetime
          import json
          file = '精選優質商品清單(內含優惠券).xls'
          def read_excel():
           wb = xlrd.open_workbook(filename=file)#打開文件
           # print(wb.sheet_names())#獲取所有表格名字
           sheet1 = wb.sheet_by_index(0)#通過索引獲取表格
           # sheet2 = wb.sheet_by_name('Page1')#通過名字獲取表格
           # print(sheet1)
           # print(sheet2)
           # print(sheet1.name) #表 名
           rows = sheet1.nrows #多少行
           # print(sheet1.ncols) #多少列
           # rows = sheet1.row_values(1)#獲取行內容
           category0 = sheet1.col_values(4)#獲取列內容(類目)
           del category0[0]
           category = sorted(set(category0),key=category0.index) #類目列表->去重
           data = []
           data_hot = []
           # print(rows)
           # print(cols)
           for i,v in enumerate(category):
           category[i] = v.replace("/", "、")#吧"/"替換"、"
           data.append([category[i],[]])
           jsonData = json.dumps(category, ensure_ascii=False)
           with open('./daogou/category.json', 'w',encoding="utf-8") as f:
           f.write(jsonData)#保存分類json
           for i,v in enumerate(data):
           for x in range(rows):
           if v[0] == (sheet1.cell(x,4).value.replace("/", "、")):
           xo = sheet1.row_values(x)
           y = [xo[1],xo[2],xo[4],xo[6],xo[21]] #選擇保存商品名稱、圖片、鏈接等
           data[i][1].append(y)
           if x>0 and float(sheet1.row_values(x)[9]) >= 1: #選擇傭金多的作為熱門
           xo = sheet1.row_values(x)
           y = [xo[1],xo[2],xo[4],xo[6],xo[21]]
           data_hot.append(y)
           data_hot = data_hot[:24]
           jsonData_hot = json.dumps(data_hot, ensure_ascii=False)
           with open('./daogou/results_hot.json', 'w',encoding="utf-8") as f:
           f.write(jsonData_hot)#保存熱門商品json
           for i,v in enumerate(data):
           jsonData = json.dumps(v[1], ensure_ascii=False)
           with open('./daogou/'+v[0]+'.json', 'w',encoding="utf-8") as f:
           f.write(jsonData)#保存每個分類商品json
           # jsonData1 = json.dumps(data, ensure_ascii=False)
           # with open('results.json', 'w',encoding="utf-8") as f:
           # f.write(jsonData1)
           # print(sheet1.cell(0,0).value)#獲取表格里的內容,第一行第一個格內容
           # print(sheet1.cell_value(0,0))#獲取表格里的內容,第一行第一個格內容
           #print(sheet1.row(0)[0].value)#獲取表格里的內容,第一行第一個格內容
          if __name__ == '__main__':
           	read_excel()
          

          創建html頁面,并引用json文件

          <!DOCTYPE html>
          <html lang="en">
          <head>
          	<meta charset="UTF-8">
          	<script src="../js/jquery.min.js"></script>
          	<link rel="stylesheet" href="../font/Alibaba-PuHuiTi-Regular.css">
          		<script>
          		var navo = '';
          var info = '';
          var data_total;//總數據
          function color16(){//十六進制顏色隨機
          	var r = Math.floor(Math.random()*256);
          	var g = Math.floor(Math.random()*256);
          	var b = Math.floor(Math.random()*256);
          	var color = '#'+r.toString(16)+g.toString(16)+b.toString(16);
          	return color;
          }
          function nav_href(title,id){//錨跳轉
          		if ($('#'+title).length>0) {
          		location.href="#"+title;
          		}else{
          			var div_title = "<div id='"+title+"' style='float:left;'>";
          			var div_content = "<div class='pro_img' style='background:#ff5000'><b style='color:#FFF'>"+title+"</b><\/div>";
          			$('#load').show();
          			$.get('./'+title+'.json', function(data) {
          				$.each(data, function(index, val) {
          					div_content+="<a style='background:"+color16()+"' target='_blank' href='"+val[4]+"' class='pro_img'><img onload='$(this).show()' src="+val[1]+" style='width:100%;height:100%;display:none;' />"+val[0]+"<span class='money'>¥"+val[3]+"</span><span class='title'>"+val[0].substring(0,25)+"...</span><\/a>";
          					if ((index+1)==data.length) {
          						var div_footer ="</div><br>";
          						infoo=div_title+div_content+div_footer;
          						$('#content').append(infoo);
          						location.href="#"+title;
          						$('#load').hide();
          					}
          						 });
          			},'json');
          			
          						 
          			
          		}
          		
          	
          }
          function get_data(){
          	$.get('./category.json', function(data) {//導航
          				$.each(data, function(index, val) {
          					 // console.log(val[0]);
          					 navo+="<a class='nav' href=javascript:;nav_href(\'"+val+"\',"+index+")>"+val+"</a> ";
          				});
          	$('#nav').html(navo);
          	$.get('./results_hot.json', function(data) {//熱門商品
          					var div_title = "<div id='熱門商品' style='float:left;'>";
          					 var div_content = "<div class='pro_img' style='background:#ff5000'><b style='color:#FFF'>熱門商品</b></span><\/div>";
          		$.each(data, function(index, val) {
          					 // console.log(val);
          					 
          					 	 div_content+="<a style='background:"+color16()+"' target='_blank' href='"+val[4]+"' class='pro_img'><img onload='$(this).show()' src="+val[1]+" style='width:100%;height:100%;display:none;' />"+val[0]+"<span class='money'>¥"+val[3]+"</span><span class='title'>"+val[0].substring(0,25)+"...</span><\/a>"
          					 
          					 
          					 // if (index==3) {return false}
          				});
          		var div_footer ="</div><br>";
          		info+=div_title+div_content+div_footer;
          	$('#content').html(info);
          	$('#load').hide(0);	
          	});
          			},'json');
          }
          	
          		
          	</script>
          	<style>
          	#body{
          		/*border: 1px solid #eee;*/
          		width: 1110px;
          		margin:0 auto;
          	}
          	a.nav{
          		text-decoration: none;
          		margin-right: 10px;
          		padding: 0 5px;
          		/*padding-bottom: 10px;*/
          		display: inline-block;
          		color: #000;
           font-weight: 700;
          	}
          	#nav{
          		display: inline-block;
          	}
          *,html,body{
          	font-family:"Alibaba-PuHuiTi-Regular";
          }
          		#content{
          			margin-top: 10px;
          			display: inline-block;
          		}
          		.money{
          	 width: 100%;
           /* padding: 0px 10px; */
           background: #ffffffcc;
           position: absolute;
           left: 0;
           bottom: 50px;
           height: 30px;
           line-height: 30px;
           color: #F40;
           font-weight: 700;
           /* border-radius: 0 8px 0 0; */
           text-align: left;
           font-size: 18px;
          		}
          				.title{
           width: 100%;
           font-weight: 700;
           /* padding: 0px 10px; */
           background: #ffffffcc;
           position: absolute;
           left: 0;
           bottom: 0;
           height: 50px;
           line-height: normal;
           color: #000;
           /* border-radius: 0 8px 0 0; */
           text-align: left;
           font-size: 15px;
          		}
          		.pro_img{
          			position: relative;
          			float: left;
          			width: 220px;
          			height: 220px;
          			line-height: 220px;
          			text-align: center;
          			border: 1px solid #eee;
          			cursor: pointer;
          			font-size: 30px;
          			/*white-space:normal; */
          			overflow:hidden; /*超過部分不顯示*/
                text-overflow:ellipsis; /*超過部分用點點表示*/
           /*     white-space:nowrap;/*不換行*/
          		}
          		.input1{
          			 width: 300px;
          			 height: 30px;
          			 border: 1px solid #888;
          				border-radius: 10px 0 0 10px;
          				outline-style: none ;
          	
          		}
          		.button1{
          			margin-left: -7px;
           width: 50px;
           height: 34px;
           border-radius:0 10px 10px 0 ;
           outline-style: none ;
          		}
          		#search1{
          			/*width: 350px;*/
          			/*margin:0 auto;*/
          		}
          		#load{
          			position: fixed;
          			width: 100%;
          			height: 100%;
          			top: 0;
          			left: 0;
          			background: #000000ad;
          			z-index: 999;
          			text-align: center;
          			vertical-align: middle;
          		}
          		#load>span{
           display: inline-block;
           vertical-align: middle;
           height: 100%;
          		}
          		.load{
          			display: inline-block;
          			vertical-align: middle;
          			font-size: 50px;
          			color: #FFF;
          		}
          	</style>
          </head>
          <body onload="get_data()">
          <!-- loading -->
          <div id="load">
          	<span ></span>
          	<div class="load">加載中...</div>
          </div>
          <div id="body">
          <h1>網站僅學習交流!!網站中的商品信息均來自于互聯網。</h1>
          <!-- 		<div id="search1">
          		<input type="text" class="input1">
          		<button class="button1">搜索</button><b> 網站僅學習交流!!網站僅學習交流!!網站僅學習交流!!網站僅學習交流!!網站僅學習交流!!</b>
          	</div> -->
          	<div id="nav"></div>
          	<div id="content"></div>
          </div>
          </body>
          </html>
          

          完成上傳json文件和html頁面到GitHub

          者 | 單雨

          責編 | 胡巍巍

          出品 | CSDN(ID:CSDNnews)

          前言

          為了實現模板封裝和復用,提高HTML界面調試便捷性以及前后端解耦等目標,Django定義了自己的網絡模板語言。

          當前介紹模板語言的官方文檔已經非常完備,幾乎涵蓋了開發中需要用到的知識點和需要注意的問題,但同時官方文檔也存在一些問題:

          • 翻譯不夠完善,帶來閱讀的困難;

          • 一些知識點的介紹過于簡短,存在大量的頁內鏈接,閱讀時需要跳轉到不同的頁面,閱讀不連貫。

          本文基于官方文檔系統介紹了Django模板語言的基礎知識點,方便快速了解Django模板語言。

          模板系統設計哲學

          Django的模板系統不是簡單的把Python嵌入到HTML中。

          它的設計宗旨是:模板系統旨在展示內容, 而不是程序邏輯,因此不在HTML頁面中嵌入Python。

          簡單的說,模板只負責渲染數據,大多數邏輯應該交給視圖(view)進行處理。

          模板簡介

          模板是一個簡單的文本文件。它可以生成任何基于文本的格式(如 HTML,XML,CSV等)。除了基本的HTML標簽外,模板還包含兩種額外的元素——變量和標簽。

          模板中包含的變量可以被替換為變量的值,標簽則被替換為相應的模板控制邏輯。示例:

          django

          {% extends "base_generic.html" %}

          {% block title %}{{ section.title }}{% endblock %}

          {% block content %}

          <h1>{{ section.title }}</h1>

          {% for story in story_list %}

          <h2>

          <a href="{{ story.get_absolute_url }}">

          {{ story.headline|upper }}

          </a>

          </h2>

          <p>{{ story.tease|truncatewords:"100" }}</p>

          {% endfor %}

          {% endblock %}

          `{{ section.title }}`在模板渲染時將會被變量的值替換,for標簽可以實現模板的循環渲染。

          基礎語法

          變量

          變量實現從模板上下文字典(返回HTTP響應時傳遞過來的字典)中輸出一個值,這是一個類似于dict的對象,包含鍵值對。當模板引擎遇到一個變量時,它會計算該變量,并用結果替換它。

          變量名由字母、數字字符和下劃線("_")組成,但不能以下劃線開頭。點(".")也出現在變量中,代表屬性調用,變量名中不能有空格或標點符號。

          示例:

          django

          My first name is {{ first_name }}. My last name is {{ last_name }}.

          當傳入一個上下文字典`{'first_name': 'John', 'last_name': 'Doe'}`時,將會渲染得到:

          django

          My first name is John. My last name is Doe.

          模板中的變量被字典中的值替換了。

          變量還可以使用點表示法實現字典查找、屬性查找和列表索引查找等操作:

          django

          {{ my_dict.key }}

          {{ my_object.attribute }}

          {{ my_list.0 }}

          點表示法底層原理

          當模板系統遇到一個點,它會按順序嘗試下面的動作:

          1. 字典查詢

          2. 屬性或方法查找

          3. 數字索引查詢

          如果結果值是可調用的,則調用該值時將不帶參數,調用的結果成為新的模板值。

          當進行能覆蓋字典查找的操作時,這種查找順序可能會造成一些意想不到的行為。例如:如果試圖循環一個collection .defaultdict字典對象:

          django

          {% for k, v in defaultdict.items %}

          {其他操作}

          {% endfor %}

          因為字典查找是首先發生的,所以這個行為會先提供一個默認值,而不是使用預期的.items方法。在這種情況下,應該首先考慮使用字典查找,而不是使用字典的屬性調用。

          注意

          屬性通常被解釋為一個文本字符串,防止和同名的變量沖突。例如{{foo.bar}}中的屬性“bar”將被解釋為一個文本字符串,如果模板上下文中存在變量“bar”,則不會使用該變量的值。

          以下劃線開頭的變量屬性可能不能訪問,因為它們通常被認為是私有的。

          如果引用不存在的變量,模板系統將插入string_if_invalid選項的值,該選項默認設置為“”(空字符串)。

          標簽

          標簽在模板渲染過程中提供任意邏輯。標簽可以輸出內容,作為控制結構,例如“if”語句或“for”循環,從數據庫獲取內容,甚至允許訪問其他模板標簽。

          (1)標簽聲明

          標簽的一般形式為:

          django

          {% tag %}

          示例:

          django

          {% csrf_token %}

          (2)傳入參數

          django

          {% cycle 'odd' 'even' %}

          (3)成對使用的標簽

          有些標簽需要開始和結束標簽:

          django

          {% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %}

          (4)常用標簽

          for:循環數組中的每個元素. 比如, 顯示列表 `athlete_list` 中每個元素的 `name` 屬性。

          django

          <ul>

          {% for athlete in athlete_list %}

          <li>{{ athlete.name }}</li>

          {% endfor %}

          </ul>

          if 、elif和else:在上面,如果athlete_list不為空,則{{athlete_list|length}}變量將顯示運動員的數量。

          否則,如果athlete_in_locker_room_list不為空,則會顯示“Athletes should be out…”消息。如果兩個列表都為空,則顯示“No athletes”。

          也可以在if標簽里使用過濾器和各種操作符:

          django

          {% if athlete_list|length > 1 %}

          Team: {% for athlete in athlete_list %} ... {% endfor %}

          {% else %}

          Athlete: {{ athlete_list.0.name }}

          {% endif %}

          注意

          雖然上面的示例可以工作,但是要注意,大多數模板過濾器都返回字符串,因此使用過濾器進行數學比較通常不會正常工作,而長度是個例外。

          (5)更多

          Django有很多內置標簽,更多關于內置標簽的信息請參考官方文檔:

          https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/ref-templates-builtins-tags

          如果需要編寫自定義標簽,請參考官方文檔

          https://docs.djangoproject.com/zh-hans/2.2/howto/custom-template-tags/howto-writing-custom-template-tags

          如果需要對使用的標簽和自定義的標簽做一份說明文檔,可以使用Django提供的文檔工具,詳情請參考:

          https://docs.djangoproject.com/zh-hans/2.2/ref/contrib/admin/admindocs/

          過濾器

          簡介

          過濾器可以對變量做一些操作,例如給變量賦值,改變變量的值等。

          修改變量顯示

          過濾器可以修改變量的顯示。例如:

          django

          {{ name|lower }}

          通過過濾器lower變量{{ name }}變為了小寫字符,通過管道符(|)間隔變量和過濾器來使用過濾器。

          鏈式調用過濾器

          一個過濾器的輸出可以作為下一個過濾器的輸入。

          {{ text|escape|linebreaks }}是一種常用的轉換方式, 在這之后換行符被替換為了 <p> 標簽。

          轉換變量和標簽參數

          過濾器轉換變量和標簽參數的值。示例:

          django

          {{ django|title }}

          傳入`{'django': 'the web framework for perfecalist With deadline '}`上下文字典時,該模板呈現為:

          django

          The Web Framework For Perfectionists With Deadlines

          傳入參數給過濾器

          示例1:

          django

          {{ my_date|date:"Y-m-d" }}

          my_date將會被替換為當前日期。

          示例2:

          django

          {{ bio|truncatewords:30 }}

          將會會顯示 `bio` 變量的前30個字符

          注意

          過濾器參數中如果包含空格和標點符號,必須使用引號“”括起來,例如,要用逗號和空格連接列表,可以使用{{list|join:", "}}。

          Django提供了大約60個內置模板過濾器,請參考官方文檔:

          https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/ref-templates-builtins-filters

          下面列舉一些常用的過濾器:

          default

          如果變量為false或空,則使用給定的默認值。否則,使用變量的值。例如:

          django

          {{ value|default:"nothing" }}

          如果 `value` 沒有提供或者為空,那么將它顯示為 "`nothing`" 。

          length

          返回值的長度。這對字符串和列表都適用。例如:

          django

          {{ value|length }}

          如果 `value` 為 `['a', 'b', 'c', 'd']`, 那么他將被顯示為 `4`。

          filesizeformat

          將值格式化為“人類可讀的”文件大小(即“13kb”、“4.1 MB”、“102字節”等)。例如:

          django

          {{ value|filesizeformat }}

          如果值為123456789,則輸出為117.7 MB。

          如果需要自定義過濾器,請參考請官方文檔:

          https://docs.djangoproject.com/zh-hans/2.2/howto/custom-template-tags/

          注釋

          示例:

          單行注釋

          django

          { this won't be rendered }

          多行注釋:{% comment %} 和{% endcomment %}

          django

          <p>Rendered text with {{ pub_date|date:"c" }}</p>

          {% comment "Optional note" %}

          <p>Commented out text with {{ create_date|date:"c" }}</p>

          {% endcomment %}

          注意:Comment標簽不能嵌套使用。

          作者簡介:單雨,90后工科男,偽文藝青年。目前就讀于北京理工大學宇航系,喜歡研究AI,網絡爬蟲,微信小程序以及機器人,癡迷于Coding,睡前必擼碼。

          【END】


          主站蜘蛛池模板: 精品国产AV无码一区二区三区| 暖暖免费高清日本一区二区三区| 亚洲天堂一区二区| 无码国产精品一区二区免费3p| 亚洲AV香蕉一区区二区三区| 视频一区视频二区制服丝袜| 亚洲午夜福利AV一区二区无码| av无码免费一区二区三区| 中文字幕aⅴ人妻一区二区 | 91精品一区国产高清在线| 国产精品无码一区二区在线观| 无码囯产精品一区二区免费| 一区二区国产在线播放| 日韩精品一区二区三区国语自制 | 狠狠做深爱婷婷综合一区 | 久久精品国产一区二区三区日韩| 日韩伦理一区二区| 国产一区在线视频观看| 亚洲a∨无码一区二区| 麻豆一区二区99久久久久| 无码精品尤物一区二区三区| 亚洲男女一区二区三区| 亚洲一区中文字幕在线电影网| 一区二区在线视频| 无码人妻啪啪一区二区| 波多野结衣中文字幕一区| 一区二区精品在线观看| 久久精品无码一区二区三区日韩| 国产一区二区女内射| 无码人妻品一区二区三区精99| 极品人妻少妇一区二区三区| av一区二区三区人妻少妇| 亚洲va乱码一区二区三区| 日韩人妻无码免费视频一区二区三区 | 国产一区二区在线视频| 国产精品亚洲一区二区麻豆| 国产伦理一区二区三区| 激情综合一区二区三区| 怡红院美国分院一区二区 | 日本一区二区免费看| 在线观看精品一区|