<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          10分鐘教你用Python爬取Baidu文庫全格式內(nèi)容

          共 7561字,需瀏覽 16分鐘

           ·

          2020-07-02 23:20


          4c610d272ac070cdc6cc5c5b4ae031d6.webp


          程序猿聲

          代碼黑科技的分享區(qū)

          07bd1e65059ce0479aed5835581a2a28.webp?


          226d9cd157f6cc23e877a08fc4d1673f.webp


          這個(gè)學(xué)期上了Python課,最后的結(jié)課方式是大作業(yè)的形式,這可把小編樂壞了。


          考慮到現(xiàn)在大部分小伙伴使用Python主要因?yàn)榕老x,那么為了更好地幫助大家鞏固爬蟲知識(shí),加深對(duì)爬蟲的理解,我們小組選擇了爬取百度文庫作為我們的大作業(yè)。


          a35aef069b0d72f97c3c1a114e5eba8b.webp


          現(xiàn)在將我們的大作業(yè)分享出來,希望能夠幫助到大家。




          本文目錄包含以下內(nèi)容:


          TXT,DOCX爬取與保存(文本格式)

          PPT,PDF爬取與保存(圖片格式)

          簡(jiǎn)單的GUI制作


          ?通過本文你將收獲:


          基本的爬蟲技能

          DOCX,Image庫的使用

          369a96888e9b70eae1e6e8313920d07a.webp


          廢話不多說,我們開始。





          1c68bcf6030182d1db1b80621658b7ae.webp





          TXT,DOCX爬取與保存

          a9bb4b3ca2663a8b2d10762fcfaf5ee7.webp


          在爬取任何東西之前,我們都要先確認(rèn)需要爬取的數(shù)據(jù)是不是異步加載的。如果是異步加載的直接爬取網(wǎng)頁是爬不到的。
          要知道是不是異步加載其實(shí)很簡(jiǎn)單,就用request對(duì)網(wǎng)頁發(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


          f74ae763252f58bcddf33946aad26a49.webp


          很明顯,返回的東西,并不是我們所需要的內(nèi)容。根據(jù)常理來說,我們就可以認(rèn)為該網(wǎng)頁是異步加載的。


          但是,從常識(shí)來講,如果網(wǎng)頁的內(nèi)容是異步加載的,那么直接通過百度搜索,是搜索不到網(wǎng)頁內(nèi)部的內(nèi)容的,但是很顯然,我們每次通過百度搜索都是可以直接找到文庫中的文本內(nèi)容的。如下:


          83e0f310a2cbe9c95d1d167b46671198.webp

          那么這就有意思了,明明直接發(fā)起請(qǐng)求是獲取不到網(wǎng)頁內(nèi)容的,但是為什么通過百度搜索就可以找到呢?


          關(guān)鍵肯定在于百度搜索上面。這個(gè)時(shí)候通過查閱資料,我們了解到,最主要的問題出在我們的headers。


          在爬取網(wǎng)頁時(shí),headers通常是作為身份證,讓網(wǎng)頁不看出我們是爬蟲。如果不加headers,網(wǎng)頁直接就會(huì)看出我們是爬蟲,就會(huì)拒絕訪問。


          14e5808b4e5d2c44e4d6f4ba867a337a.webp


          再深入了解以下headers的識(shí)別機(jī)理,我們發(fā)現(xiàn)了叫做Robot協(xié)議的東西。


          它規(guī)定了什么樣的headers可以訪問網(wǎng)頁內(nèi)部?jī)?nèi)容,除了指定headers之外的headers,都是無法請(qǐng)求頁面內(nèi)容的。(更詳細(xì)的Robot協(xié)議介紹以附件形式給出)


          比如說百度文庫的Robot協(xié)議就是下面這樣的。


          User-agent:?Baiduspider

          Disallow:?/w?

          Disallow:?/search?

          Disallow:?/submit

          Disallow:?/upload

          Disallow:?/cashier/???


          而我們需要爬取的內(nèi)容url格式為


          https://wenku.baidu.com/view/?.html


          這代表Baiduspider應(yīng)該可以爬取文庫內(nèi)容。大致猜測(cè)這是因?yàn)榘俣人阉鲿r(shí)需要根據(jù)文本內(nèi)容匹配搜索選項(xiàng),所以放行。


          因此我們嘗試偽裝User-agent為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)容。


          2ab80d2ea51701cadef8f5566bacf53c.webp


          既然已經(jīng)成功獲取到了網(wǎng)頁的正確源代碼,那么下一步就是去解析網(wǎng)頁獲取內(nèi)容。


          解析網(wǎng)頁源代碼的庫有很多,這里我們使用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)的操作。在這里就不多加敘述了。最終的效果如下。


          cbc9c41f2ef476ab8da328ba12ff1670.webp


          當(dāng)然爬取到東西了只是萬里長征的第一步,就這樣是肯定不行的,我們還需要將爬取的內(nèi)容保存起來,通常是保存為txt文件。


          file?=?open('test.txt',?'w',encoding='utf-8')
          for?str?in?plist:
          ????file.write(str)
          ????file.write('\n')
          file.close()


          a1d0321449bb3fb29b37c81e7b199a5c.webp


          但是為了美觀起見,我們?cè)谶@里選擇使用python-docx庫將內(nèi)容保存為docx文件。


          with?open('test.txt',?encoding='utf-8')?as?f:
          ????docu?=?Document()
          ????docu.add_paragraph(f.read())
          ????docu.save('test.docx')


          17a422bc1b7b2e005f444ce4cc2f6fe1.webp




          PPT,PDF爬取與保存

          a9bb4b3ca2663a8b2d10762fcfaf5ee7.webp


          有了之前的經(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)容的。


          989c5202afe0b71c63cf07110946d1e9.webp


          那么很顯然,PPT和PDF是通過異步的方法進(jìn)行內(nèi)容加載的。


          對(duì)待異步加載的數(shù)據(jù),我們通常采取的策略有兩種,第一個(gè)就是直接找到發(fā)起異步請(qǐng)求的接口,自己構(gòu)造請(qǐng)求頭,發(fā)起請(qǐng)求,第二個(gè)就是通過Selenium這樣的自動(dòng)化測(cè)試工具去爬取。


          e4a76c86b2318d9cfe9ec0a089efcf75.webp


          百度文庫的接口太難找了,請(qǐng)求頭的構(gòu)造也很麻煩,找了很久也沒有很滿意。所以在本次爬取中,我們使用的是第二種方法,使用Selenium這樣的自動(dòng)化測(cè)試工具。

          efb2b722a257e3a397fe7a1dea19e6c7.webp

          在這里不多加介紹WebDriver,有興趣的小伙伴可以自己查一下,我們直接上手使用。


          這里我們需要下載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)行不起來的。


          2d582cb1f3c1297b741d11e8472ba8eb.webp


          我們先不急著馬上開始爬取,我們先來嘗試使用一下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)頁的正確源代碼已經(jīng)在里面了。


          現(xiàn)在我們仔細(xì)研究一下源代碼就可以看到,我們需要的內(nèi)容在下面這個(gè)位置。


          fd2baa9ff684e49a997464464cc4b3f0.webp


          現(xiàn)在正確的源代碼也有了,內(nèi)容的位置也知道了,直接解析,爬取,完事就好了。


          b163906f9d0af13e3134d71132a4b02e.webp


          想得美,經(jīng)過這樣的爬取之后,對(duì)內(nèi)容進(jìn)行解析,讓我們看看究竟爬到?jīng)]有。


          69691e690a804c959296fd21aede5a86.webp


          from?lxml?import?etree
          import?re
          html=etree.HTML(driver.page_source)
          links=html.xpath("http://div[@class='reader-pic-item']/@style")
          part?=?re.compile(r'url[(](.*?)[)]')
          qa="".join(links)
          z=part.findall(qa)
          z


          779ab6a285c0829b7cb3af159d6edfb8.webp


          我們可以知道,其實(shí)我們只爬到3張PDF,其他的都沒有爬到。這是為什么呢?


          這是百度文庫為了防止大家去爬,專門設(shè)置的一個(gè)小機(jī)關(guān)。


          d3cec6452043d117281a1c595d742676.webp


          返回百度文庫,我們仔細(xì)看看源代碼,其實(shí)我們可以發(fā)現(xiàn),隨著頁面的變化,源代碼是不斷改變的,每次都只有3張圖片的url。并且這個(gè)頁碼數(shù)也有一定的規(guī)律,如果在第二頁,那么圖片就是1,2,3,如果在第三頁,圖片就是2,3,4。


          673174dd8cc5412fcf8108fd839fe474.webp


          那么我們的疑惑一下就解決了,只需要不斷地進(jìn)行換頁的爬取,就可以了。接下來就是如何實(shí)現(xiàn)換頁的操作了。


          這個(gè)需要兩個(gè)步驟,先是點(diǎn)擊繼續(xù)閱讀,然后進(jìn)行頁面輸入實(shí)現(xiàn)換頁。先實(shí)現(xiàn)點(diǎn)擊的操作,代碼如下。


          button?=?driver.find_element_by_xpath("http://*[@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í)候直接用就可以。


          然后就是輸入頁面實(shí)現(xiàn)換頁,這個(gè)其實(shí)涉及的比較多,細(xì)分的話,步驟分為獲取總頁數(shù),依次輸入頁面并點(diǎn)擊。


          import?re
          #?尋找頁面
          source?=?re.compile(r'/(.*?)')
          number?=?int(source.findall(driver.page_source)[0])
          #?輸入頁面并點(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了。


          9c5d94640f70afc4971842fac00aa3bf.webp


          因?yàn)榕廊DF和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鏋镻DF的時(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文件。


          8d12e09cca8bc896790579935d7ae0d5.webp


          上述的操作看起來很多,很麻煩,其實(shí)并不是的。因?yàn)榇蟛糠值牟僮鞫际枪潭ǖ模蠹抑恍枰浭炀涂梢粤恕?/span>




          簡(jiǎn)單的GUI制作

          a9bb4b3ca2663a8b2d10762fcfaf5ee7.webp


          GUI這塊,我們整了點(diǎn)新活兒,用C#編寫winform簡(jiǎn)易的GUI,調(diào)用爬蟲的python代碼。


          44a43372652eb2551c67bd6dd3742da7.webp


          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)單判斷,如果不是百度文庫地址或不是python.exe地址,報(bào)錯(cuò)。

          if?(!url.Contains("https://wenku.baidu.com/view/"))
          {
          ????MessageBox.Show("請(qǐng)輸入正確的百度文庫網(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)镚UI部分比較簡(jiǎn)單,學(xué)過C#的同學(xué)應(yīng)該都看的明白(沒學(xué)過的呢?),這里就不多講解了。




          代碼下載

          a9bb4b3ca2663a8b2d10762fcfaf5ee7.webp


          具體代碼比較長,就不在此展示了,有興趣的朋友可以在公眾號(hào)內(nèi)輸入【PYWENKU】不帶【】,即可下載對(duì)應(yīng)python、C#代碼,以及完整的項(xiàng)目文件。


          推薦閱讀:

          干貨 | 想學(xué)習(xí)優(yōu)化算法,不知從何學(xué)起?

          干貨 | 運(yùn)籌學(xué)從何學(xué)起?如何快速入門運(yùn)籌學(xué)算法?

          干貨 | 學(xué)習(xí)算法,你需要掌握這些編程基礎(chǔ)(包含JAVA和C++)

          干貨 | 算法學(xué)習(xí)必備訣竅:算法可視化解密

          干貨 | 模擬退火、禁忌搜索、迭代局部搜索求解TSP問題Python代碼分享
          記得點(diǎn)個(gè)在看支持下哦~c915110f7f72f9c502e7fa4d7f1b77c7.webp
          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色一级免费视频 | 午夜福利视频在线 | 日日射视频 | 一区二区三区免费 | 欧美十八禁网站 |