Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
NET平臺(tái)的VS2019還是挺爽手的IDE,寫WinForm較寫WebForm程序?qū)懫饋矸奖悖吘鬼?xiàng)目所需資源基本上都在本地,而WebForm不僅需要IIS支持,還需要其它Script幫助。據(jù)說MS出了ASP5,微軟自己用的網(wǎng)絡(luò)平臺(tái)是基于.NET和ASP5的。MS能跑在.NET和ASP上,其它小網(wǎng)站當(dāng)然不在話下。其實(shí)VS2019上,有MVC模式可參選,但初步印象好像不是Ruby on Rail那樣的MVC實(shí)例化了。先搭個(gè)WebForm找找感覺,如果能激發(fā)出足夠的熱情,后面的事就好開展了。
1. 在Win10上創(chuàng)建IIS服務(wù)
2. 用VS2019 C#試練ASP的WebForm
在Win10上找到控制面版,打開它,點(diǎn)類別選圖標(biāo)方式。
圖標(biāo)方式列出各分項(xiàng)功能,找到“程序和功能”項(xiàng)。?
進(jìn)入程序和功能,找到左上角的“啟用或關(guān)閉Windows功能” ?
在彈出頁(yè)面上點(diǎn)選Internet Information Services和Internet Information Services可承載的Web核心項(xiàng) ?
點(diǎn)擊確定后,打開本地瀏覽器,輸入localhost,也就是127.0.0.1,IIS默認(rèn)的首頁(yè)就出來了,說明IIS啟用正常。?
在VS2019上新建項(xiàng)目,選ASP.NET Web 應(yīng)用程序(.NET Framework)項(xiàng)。由于列示的模板比較多,要耐心點(diǎn)找到它。?
雙擊它,即進(jìn)入配置新項(xiàng)目頁(yè)。在此頁(yè)將位置設(shè)置一下,比如 E:\aspnet1 ?
其它名字和框架之類的就用默認(rèn)的吧。然后,點(diǎn)擊創(chuàng)建,之后的頁(yè)面上選空項(xiàng)目模板,其它的默認(rèn)。接下來,點(diǎn)擊創(chuàng)建。?
在資源管理器的項(xiàng)目WebApplication1黑體字上點(diǎn)右鍵,添加,新建項(xiàng)。?
在新建項(xiàng)出來的頁(yè)面上,點(diǎn)選畫著藍(lán)色圓皮球的 “Web”窗體。?
資源管理器內(nèi)容變成這個(gè)樣子 ?
源,即前臺(tái)瀏覽器的代碼;設(shè)計(jì),即web界面。WEB界面設(shè)計(jì)與WinForm類似但不同,虛格里面是放控件的地方,可以點(diǎn)擊伸縮它。其上面可插入HTML標(biāo)記,SCRIPT標(biāo)記等(IIS支持的腳本均可用,也可以給IIS安裝擴(kuò)展其它比如Perl的解釋器等),這些操作可以在“源”里直接編輯的。?
?
在設(shè)計(jì)頁(yè),點(diǎn)左邊“工具箱”,將Label,Button分別拖到界面上。在“源”頁(yè),加上<H2></H2>標(biāo)記的一行大字“A simple WebPage of ASP.NET”,再一行普通<p></p>標(biāo)記的小字“On Microsoft VS2019 IDE, C# is a good partner of ASP.NET for dynamic webpages”,在設(shè)計(jì)頁(yè)面也可以改寫它們的。?
接下來,是雙擊Button,寫上C#代碼。
- 點(diǎn)擊Button,改換Label1和Label2的文字
- 點(diǎn)擊Button, 寫文本文件再讀出記錄顯示在Label上(加上幾行ADO的代碼,可以操作數(shù)據(jù)庫(kù)的)?
Ctrl+S 保存, Ctrl+B生成,然后運(yùn)行,Edge瀏覽器顯示如圖。?
瀏覽器被自動(dòng)打開,所做的WebForm頁(yè)就顯示出來了。如果你的計(jì)算機(jī)有公網(wǎng)固定IP地址,在遙遠(yuǎn)的互聯(lián)網(wǎng)上也能看到你的主頁(yè)的。
因?yàn)槭情_發(fā)方式,不是正式的部署,它并未使用IIS默認(rèn)的80端口,遠(yuǎn)程訪問時(shí)不能只訪問IP地址,要帶上端口號(hào)。如果沒有公網(wǎng)固定IP地址,可以申請(qǐng)花生殼免費(fèi)的賬號(hào),安上它的軟件即可穿透小區(qū)網(wǎng),把你的計(jì)算機(jī)反向代理到公網(wǎng),互聯(lián)網(wǎng)上即可以訪問你的計(jì)算機(jī)。這離做個(gè)真實(shí)像樣的網(wǎng)站還有很多距離,沒做母板也沒有活動(dòng)頁(yè),數(shù)據(jù)和頁(yè)面傻傻的不能實(shí)時(shí)變化數(shù)據(jù),數(shù)據(jù)庫(kù)沒帶上,但搭了架子可以讓各種Script語(yǔ)言幫助解決。MVC三層模型好是好,看了看VBSCRIP寫的ASP.NET的POPASP的MVC資料,覺得它的最后一版可以快速開發(fā)站點(diǎn)用了。哎,亂七八糟的一堆東西,了解一下還好,真要做事還是要辛苦得多。
??
慮到現(xiàn)在大部分小伙伴使用 Python 主要因?yàn)榕老x,那么為了更好地幫助大家鞏固爬蟲知識(shí),加深對(duì)爬蟲的理解,選擇了爬取百度文庫(kù)作為我們的目標(biāo)。
TXT、DOCX 爬取與保存
這是小編準(zhǔn)備的python基礎(chǔ)學(xué)習(xí)資料,關(guān)注,轉(zhuǎn)發(fā),私信小編“01”即可免費(fèi)領(lǐng)取!
在爬取任何東西之前,我們都要先確認(rèn)需要爬取的數(shù)據(jù)是不是異步加載的;如果是異步加載的直接爬取網(wǎng)頁(yè)是爬不到的。
要知道是不是異步加載其實(shí)很簡(jiǎn)單,就用requests 對(duì)網(wǎng)頁(yè)發(fā)起請(qǐng)求,看看 response 是什么就可以了
url = 'https://wenku.baidu.com/view/4e29e5a730126edb6f1aff00bed5b9f3f90f72e7.html?rec_flag=default'
header = {'User-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'}
res = requests.get(url , headers = header)
res.text
很明顯,返回的東西,并不是我們所需要的內(nèi)容; 根據(jù)常理來說,我們就可以認(rèn)為該網(wǎng)頁(yè)是異步加載的。
但是,從常識(shí)來講,如果網(wǎng)頁(yè)的內(nèi)容是異步加載的,那么直接通過百度搜索,是搜索不到網(wǎng)頁(yè)內(nèi)部的內(nèi)容的,但是很顯然,我們每次通過百度搜索都是可以直接找到文庫(kù)中的文本內(nèi)容的。
如下:
那么這就有意思了,明明直接發(fā)起請(qǐng)求是獲取不到網(wǎng)頁(yè)內(nèi)容的,但是為什么通過百度搜索就可以找到呢? 關(guān)鍵肯定在于百度搜索 上面。
這個(gè)時(shí)候通過查閱資料,我們了解到,最主要的問題出在我們的 headers
在爬取網(wǎng)頁(yè)時(shí),headers 通常是作為身份證,讓網(wǎng)頁(yè)不看出我們是爬蟲;如果不加 headers,網(wǎng)頁(yè)直接就會(huì)看出我們是爬蟲,就會(huì)拒絕訪問
再深入了解一下 headers 的識(shí)別機(jī)理,我們發(fā)現(xiàn)了叫做 Robot 協(xié)議的東西。
它規(guī)定了什么樣的 headers 可以訪問網(wǎng)頁(yè)內(nèi)部?jī)?nèi)容,除了指定 headers 之外的 headers,都是無法請(qǐng)求頁(yè)面內(nèi)容的。
比如說百度文庫(kù)的 Robot 協(xié)議就是下面這樣的:
User-agent: Baiduspider
Disallow: /w?
Disallow: /search?
Disallow: /submit
Disallow: /upload
Disallow: /cashier/
而我們需要爬取的內(nèi)容 url 格式為
這代表 Baiduspider 應(yīng)該可以爬取文庫(kù)內(nèi)容;大致猜測(cè)這是因?yàn)榘俣人阉鲿r(shí)需要根據(jù)文本內(nèi)容匹配搜索選項(xiàng),所以放行。
因此我們嘗試偽裝 UA 為 Baiduspider
url = 'https://wenku.baidu.com/view/4e29e5a730126edb6f1aff00bed5b9f3f90f72e7.html?rec_flag=default'
header = {'User-agent': 'Googlebot'}
res = requests.get(url , headers = header)
res.text
果然不出所料,我們成功地獲取到了目標(biāo)內(nèi)容
既然已經(jīng)成功獲取到了網(wǎng)頁(yè)的正確源代碼,那么下一步就是去解析網(wǎng)頁(yè)獲取內(nèi)容。
解析網(wǎng)頁(yè)源代碼的庫(kù)有很多,這里我們使用 BeautifulSoup
plist = []
soup = BeautifulSoup(r, "html.parser")
plist.append(soup.title.string)
for div in soup.find_all('div', attrs={"class": "bd doc-reader"}):
plist.extend(div.get_text().split('\n'))
plist = [c.replace(' ', '') for c in plist]
plist = [c.replace('\x0c', '') for c in plist]
plist
整個(gè)解析是非常容易的,都是很標(biāo)準(zhǔn)的操作。
在這里就不多加敘述了,最終的效果如下:
當(dāng)然爬取到東西了只是萬里長(zhǎng)征的第一步,就這樣是肯定不行的,我們還需要將爬取的內(nèi)容保存起來,通常是保存為 txt 文件
file = open('test.txt', 'w',encoding='utf-8')
for str in plist:
file.write(str)
file.write('\n')
file.close()
但是為了美觀起見,我們?cè)谶@里選擇使用 python-docx 庫(kù)將內(nèi)容保存為 docx 文件
with open('test.txt', encoding='utf-8') as f:
docu = Document()
docu.add_paragraph(f.read())
docu.save('test.docx')
PPT、PDF 爬取與保存
有了之前的經(jīng)驗(yàn)教訓(xùn),在爬取的時(shí)候我們首先就嘗試了使用爬取 TXT、DOCX 的方法,嘗試是否可以爬到內(nèi)容
url = 'https://wenku.baidu.com/view/a4ac1b57dd88d0d232d46a0f.html?fr=search'
header = {'User-agent': 'Googlebot'}
res = requests.get(url , headers = header)
res.text
很可惜的是,我們并沒有訪問到
原因仔細(xì)想想也很簡(jiǎn)單,在百度搜索的時(shí)候,直接搜索是搜不到 PPT 或者 PDF 的內(nèi)容的
那么很顯然,PPT 和 PDF 是通過異步的方法進(jìn)行內(nèi)容加載的
對(duì)待異步加載的數(shù)據(jù),我們通常采取的策略有兩種
1、第一個(gè)就是直接找到發(fā)起異步請(qǐng)求的接口,自己構(gòu)造請(qǐng)求頭,發(fā)起請(qǐng)求
2、第二個(gè)就是通過 Selenium 這樣的自動(dòng)化測(cè)試工具去爬取
百度文庫(kù)的接口太難找了,請(qǐng)求頭的構(gòu)造也很麻煩,找了很久也沒有很滿意。
所以在本次爬取中,我們使用的是第二種方法,使用 Selenium 這樣的自動(dòng)化測(cè)試工具
這里我們需要下載 ChromeDriver 這個(gè)插件,當(dāng)然這里是默認(rèn)大家使用的是 Chrome 瀏覽器,如果是其他的瀏覽器,firefox,safari 等等,直接去網(wǎng)上找到相應(yīng) Driver 就可以了。
這里給出 ChromeDriver 的下載地址
http://npm.taobao.org/mirrors/chromedriver/
大家一定要下載和自己 Chrome 瀏覽器版本一致的 ChromeDriver,不然程序是運(yùn)行會(huì)報(bào)錯(cuò)
我們先不急著馬上開始爬取,我們先來嘗試使用一下Selenium調(diào)用ChromeDriver
import requests
from selenium import webdriver
url = 'https://wenku.baidu.com/view/5292b2bc0166f5335a8102d276a20029bd64638c.html?fr=search'
driver = webdriver.Chrome(r'F:\driver\chromedriver.exe')
driver.get(url)
怎么樣,是不是瀏覽器自動(dòng)打開了? 現(xiàn)在我們嘗試輸出這個(gè) driver,就可以看見,網(wǎng)頁(yè)的正確源代碼已經(jīng)在里面了
現(xiàn)在我們仔細(xì)研究一下源代碼就可以看到,我們需要的內(nèi)容在下面這個(gè)位置
現(xiàn)在正確的源代碼也有了,內(nèi)容的位置也知道了,直接解析,爬取,完事就好了。
想得美,經(jīng)過這樣的爬取之后,對(duì)內(nèi)容進(jìn)行解析,讓我們看看究竟爬到?jīng)]有
from lxml import etree
import re
html=etree.HTML(driver.page_source)
links=html.xpath("//div[@class='reader-pic-item']/@style")
part = re.compile(r'url[(](.*?)[)]')
qa="".join(links)
z=part.findall(qa)
z
我們可以知道,其實(shí)我們只爬到 3 張 PDF,其他的都沒有爬到。
這是為什么呢?
這是百度文庫(kù)為了防止大家去爬,專門設(shè)置的一個(gè)小機(jī)關(guān)
返回百度文庫(kù),我們仔細(xì)看看源代碼,其實(shí)我們可以發(fā)現(xiàn),隨著頁(yè)面的變化,源代碼是不斷改變的,每次都只有 3 張圖片的 url。
并且這個(gè)頁(yè)碼數(shù)也有一定的規(guī)律,如果在第二頁(yè),那么圖片就是 1,2,3,如果在第三頁(yè),圖片就是 2,3,4
那么我們的疑惑一下就解決了,只需要不斷地進(jìn)行換頁(yè)的爬取,就可以了
接下來就是如何實(shí)現(xiàn)換頁(yè)的操作了
這個(gè)需要兩個(gè)步驟,先是點(diǎn)擊繼續(xù)閱讀,然后進(jìn)行頁(yè)面輸入實(shí)現(xiàn)換頁(yè)。
先實(shí)現(xiàn)點(diǎn)擊的操作,代碼如下:
button = driver.find_element_by_xpath("//*[@id='html-reader-go-more']/div[2]/div[1]/span")
button.click()
driver.execute_script("arguments[0].click();", button)
整個(gè)操作是通過 JS 來進(jìn)行的,大家可以把這個(gè)記住,以后需要點(diǎn)擊的時(shí)候直接用就可以
然后就是輸入頁(yè)面實(shí)現(xiàn)換頁(yè),這個(gè)其實(shí)涉及的比較多,細(xì)分的話,步驟分為獲取總頁(yè)數(shù),依次輸入頁(yè)面并點(diǎn)擊。
import re
# 尋找頁(yè)面
source = re.compile(r'<span class="page-count">/(.*?)</span>')
number = int(source.findall(driver.page_source)[0])
# 輸入頁(yè)面并點(diǎn)擊
driver.find_element_by_class_name("page-input").clear()
driver.find_element_by_class_name("page-input").send_keys('2')
driver.find_element_by_class_name("page-input").send_keys(Keys.ENTER)
如果小伙伴成功實(shí)現(xiàn)了上面的操作,其實(shí)大體的爬取工作已經(jīng)差不多了,接下來就是保存我們的 PPT 和 PDF了
因?yàn)榕廊?PDF 和 PPT 的時(shí)候,我們是爬取的圖片的源地址,那么我們要獲得這張圖片并保存下來就必須對(duì)這個(gè)地址發(fā)起請(qǐng)求,然后將返回頭以二進(jìn)制保存下來。
for m in range(3):
pic = requests.get(z[m]).content
# 方法一
# file = open(f'./照片/{m+1}.jpg','wb')
# file.write(pic)
# file.close()
# 方法二
with open(f'./照片/{m+1}.jpg','wb') as f:
f.write(pic)
f.close()
在這里,提醒大家一下一定要按照對(duì)圖片用正確順序進(jìn)行命名,因?yàn)楹竺姹4鏋?PDF 的時(shí)候,需要排序
在 py 文件的目錄下,大家就可以看見保存下來的圖片了
最后一步,將圖片保存為 PDF
from PIL import Image
import os
folderPath = "F:/TEST"
filename = "test"
files = os.listdir(folderPath)
jpgFiles = []
sources = []
for file in files:
if 'jpg' in file:
jpgFiles.append(file)
tep = []
for i in jpgFiles:
ex = i.split('.')
tep.append(int(ex[0]))
tep.sort()
jpgFiles=[folderPath +'/'+ str(i) + '.jpg' for i in tep]
output = Image.open(jpgFiles[0])
jpgFiles.pop(0)
for file in jpgFiles:
img = Image.open(file)
img = img.convert("P")
sources.append(img)
output.save(f"./{filename}.pdf","PDF",save_all=True,append_images=sources)
最終的結(jié)果就是生成了咱們的 PDF 文件
上述的操作看起來很多,很麻煩,其實(shí)并不是的,因?yàn)榇蟛糠值牟僮鞫际枪潭ǖ模蠹抑恍枰浭炀涂梢粤恕?/p>
簡(jiǎn)單的 GUI 制作
GUI 這塊,我們整了點(diǎn)新活兒,用 C# 編寫 winform 簡(jiǎn)易的 GUI,調(diào)用爬蟲的 Py thon 代碼
C# 調(diào)用 python 項(xiàng)目的方式我簡(jiǎn)單用 Process 類執(zhí)行,通過執(zhí)行 python.exe 執(zhí)行代碼
public static void RunPythonScript(string sArgName, string py, string args = "", params string[] teps)
{
Process p = new Process();
//(沒放debug下,寫絕對(duì)路徑)
//string path = @"C:\Users\zll\Desktop\baidu\CSharpCallPython\bin\Debug\" + sArgName;
// 獲得python文件的絕對(duì)路徑(將文件放在c#的debug文件夾中可以這樣操作)
string path = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + sArgName;
//沒有配環(huán)境變量的話,可以像我這樣寫python.exe的絕對(duì)路徑。如果配了,直接寫"python.exe"即可
//p.StartInfo.FileName = @"C:\Users\zll\AppData\Local\Programs\Python\Python37-32\python.exe";
p.StartInfo.FileName = @py;
string sArguments = path;
foreach (string sigstr in teps)
{
sArguments += " " + sigstr;//傳遞參數(shù)
}
sArguments += " " + args;
p.StartInfo.Arguments = sArguments;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.Start();
p.BeginOutputReadLine();
p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
Console.ReadLine();
p.WaitForExit();
}
對(duì)輸入 的內(nèi)容進(jìn)行簡(jiǎn)單判斷,如果不是百度文庫(kù)地址或不是 python.exe 地址,報(bào)錯(cuò)
if (!url.Contains("https://wenku.baidu.com/view/"))
{
MessageBox.Show("請(qǐng)輸入正確的百度文庫(kù)網(wǎng)址!");
lbl_state.Text = "請(qǐng)重新輸入。";
}
else if (!py.Contains("python.exe"))
{
MessageBox.Show("請(qǐng)輸入正確的python.exe路徑!");
lbl_state.Text = "請(qǐng)重新輸入。";
}
else
{
//輸入?yún)?shù)列表
String[] strArr = new String[] { url, istxt };
string sArguments = @"src\wenku.py";//這里是python的文件名字
RunPythonScript(sArguments, py, "-u", strArr);
if(result.Contains("0"))
lbl_state.Text = "對(duì)不起,爬取失敗。";
else if (result.Contains("1"))
lbl_state.Text = "爬取成功!";
}
因?yàn)?GUI 部分比較簡(jiǎn)單,這里就不過多描述了。
、使用性能測(cè)試工具dotTrace 3.0,它能夠計(jì)算出你程序中那些代碼占用內(nèi)存較多(下載網(wǎng)址:http://www.xue51.com/soft/4836.html)
2、強(qiáng)制垃圾回收
3、多dispose,close
4、用timer,每幾秒鐘調(diào)用:SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);具體見附錄。
5、發(fā)布的時(shí)候選擇Release
6、注意代碼編寫時(shí)少產(chǎn)生垃圾,比如String + String就會(huì)產(chǎn)生大量的垃圾,可以用StringBuffer.Append
7、this.Dispose(); this.Dispose(True); this.Close(); GC.Collect();
8、注意變量的作用域,具體說某個(gè)變量如果只是臨時(shí)使用就不要定義成成員變量。GC是根據(jù)關(guān)系網(wǎng)去回收資源的。
9、檢測(cè)是否存在內(nèi)存泄漏的情況,詳情可參見:內(nèi)存泄漏百度百科
定期清理執(zhí)行垃圾回收代碼:
#region 內(nèi)存回收
[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
/// <summary>
/// 釋放內(nèi)存
/// </summary>
public static void ClearMemory()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
App.SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
}
#endregion
(轉(zhuǎn)自:www.cnblogs.com的心存善念,至于他轉(zhuǎn)的那里,我就不知道了。。。。)
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。