<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>

          爬蟲案例:手把手教你爬取圖片

          共 8705字,需瀏覽 18分鐘

           ·

          2020-11-21 21:28

          一、確認(rèn)目標(biāo)和思路:

          寫在最前面:程序很簡單,重要的是思路以及對錯(cuò)誤的分析

          1.確認(rèn)目標(biāo)和大體思路:

          今天我們需要爬取的網(wǎng)站是:http://www.bbsnet.com/doutu

          下面是網(wǎng)站的首頁:

          可以看見,這個(gè)網(wǎng)站的特點(diǎn)是,一個(gè)圖片是一系列圖片的集合,因此我們需要先獲取每一個(gè)圖片的地址,然后跳轉(zhuǎn)進(jìn)去才能獲取里面真正的圖片。

          接下來我們首先獲取第一頁的圖片地址,一般來說,第一頁與其他頁的差別就在于url的一些小差別,因此,搞定第一頁等于搞定所有。

          下面開始盤它。

          補(bǔ)充:我們下面使用requets庫請求和xpath來解析(附贈(zèng)正則解析方法)

          二、分析與編寫代碼:

          1.第一步導(dǎo)入庫:

          #導(dǎo)包
          from?lxml?import?etree
          import?requests
          import?re
          import?time

          2.第二步寫出大體框架:

          這里我們還是采用面向?qū)ο髞韺?,因?yàn)檫@樣后期如果要改為多線程還是挺容易的。

          class?MySpider(object):
          ????def?__init__(self):
          ????????#顯然我們需要最基礎(chǔ)的headers信息
          ????????self.headers?=?{
          ????????????'User-Agent':'Mozilla/5.0?(Windows?NT?10.0;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/86.0.4240.75?Safari/537.36',
          ????????}
          ????????#其次我們需要url
          ????????self.url?=?'http://www.bbsnet.com/doutu'
          ????
          ????def?run(self):
          ????????#首先我們需要一個(gè)函數(shù)獲取每一個(gè)url
          ????????target_urls?=?self.get_target_urls()
          ????????#其次我們需要去獲取每一個(gè)url里面的圖片
          ????????self.get_target_images(target_urls)
          ????????
          ????def?get_target_urls(self):
          ????????'''這里我們使用一個(gè)東西,比如列表等來存儲(chǔ)url的結(jié)果并返回'''
          ????????pass

          ????def?get_target_images(self,target_urls):
          ????????'''這里我們需要接收之前獲取的url,所以需要一個(gè)參數(shù)'''
          ????????pass

          if?__name__?==?'__main__':
          ????spider?=?MySpider()
          ????spider.run()

          顯然上面的代碼跟我們的思路一模一樣,是不是so easy。

          3.第三步完成第一個(gè)函數(shù) -- get_target_urls():

          首先按照慣例,寫下以下代碼:

          response?=?requests.get(self.url,headers=self.headers)
          print(response.content.decode('utf-8'))

          首先,分享下為什么有的時(shí)候我們對于文本要decode('utf-8'),而有時(shí)候?qū)τ谖谋拘枰猟ecode('gbk'),這是根據(jù)網(wǎng)頁源代碼的編碼形式來寫的,比如這個(gè)網(wǎng)站的源代碼如下:


          但是,嘗試運(yùn)行了下,發(fā)現(xiàn)以下錯(cuò)誤:

          UnicodeEncodeError:?'gbk'?codec?can't?encode?character?'\u2009'?in?position?424:?illegal?multibyte?sequence

          這個(gè)意思是說,這個(gè)網(wǎng)頁存在一些字符是utf-8無法解碼的,這是很正常的,畢竟有些神奇的字符,是utf-8無法表示的。

          但是,大家不必緊張,這并不影響我們寫代碼。于是我們就這樣吧,不解碼了,直接以二進(jìn)制的形式存儲(chǔ)它,因?yàn)樗⒉挥绊懳覀內(nèi)カ@取我們需要的鏈接。

          于是寫下這樣代碼:

          response?=?requests.get(self.url,headers=self.headers)
          text?=?response.content

          好的,下面我們開始解析網(wǎng)頁:


          可以得到以下結(jié)果:


          下面我們使用xpath來解析這個(gè)html代碼,我們首先如上圖定位a標(biāo)簽,顯然這個(gè)a標(biāo)簽在h2標(biāo)簽里面,且這個(gè)h2標(biāo)簽里面只有這么一個(gè)a標(biāo)簽,所以十分容易獲取,代碼如下:

          html?=?etree.HTML(text)
          target_urls?=?html.xpath('//h2/a/@href')
          print(target_urls)

          下面是嘗試打印的結(jié)果(部分):

          ['http://www.bbsnet.com/aoteman.html',?'http://www.bbsnet.com/jieqian.html',?'http://www.bbsnet.com/youxitu.html',?'http://www.bbsnet.com/liaotian-3.html',......]

          好的,至此,這個(gè)函數(shù)就完成了,是不是十分簡單。該函數(shù)代碼如下:

          def?get_target_urls(self):
          ?response?=?requests.get(self.url,headers=self.headers)
          ????text?=?response.content
          ?html?=?etree.HTML(text)
          ????target_urls?=?html.xpath('//h2/a/@href')
          ?return?target_urls

          4.第四步完成第二個(gè)函數(shù) --get_target_images():

          老套路,寫下下面的代碼:

          for?url?in?target_urls:
          ????response?=?requests.get(url,headers=self.headers)
          ????text?=?response.content.decode('utf-8')
          ????print(text)
          ????#這里強(qiáng)烈建議加上break測試
          ????break

          于是,得到下面的結(jié)果:

          <html><head><script?type="text/javascript">function?f(){window.location.href="http://www.bbsnet.com/aoteman.html";}script>head><body?onload="f()"><img?style="display:none"?src="http://tieba.baidu.com/_PXCK_7132125338940_2652120900.gif"?/>body>html>

          好吧,顯然這并不是我們需要的結(jié)果,那這是什么呢?這段代碼(html代碼)會(huì)自動(dòng)把我們重定向到首頁,這樣我們顯然獲取不成功,于是,我們怎么辦呢?在訪問一次就可以了,我們僅需要在加上一次請求即可獲取所需的html代碼。如下:

          for?url?in?target_urls:
          ????response?=?requests.get(url,headers=self.headers)
          ????response?=?requests.get(url,headers=self.headers)
          ????text?=?response.content
          ????#這里同上面,不解碼,直接解析,原因同上
          ????print(text)
          ????break

          結(jié)果如下(部分結(jié)果):

          b'html?PUBLIC?"-//W3C//DTD?XHTML?1.0?Transitional//EN"?"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r\n<html?xmlns="http://www.w3.org/1999/xhtml">\r\n<head?profile="http://gmpg.org/xfn/11">\r\n<meta?charset="UTF-8">\r\n<meta?http-equiv="Content-Type"?content="text/html"?/>\r\n<meta?name="referrer"?content="no-referrer"?/>.......

          好的,解決了這個(gè)大麻煩,我們下面的工作就很簡單了。


          可以得到以下內(nèi)容:

          我們需要獲取img標(biāo)簽里面的src屬性,僅需獲取div標(biāo)簽下的p標(biāo)簽下的img標(biāo)簽即可。下面是代碼:

          for?url?in?target_urls:
          ????response?=?requests.get(url,headers=self.headers)
          ????time.sleep(2)?#一定要加上,不然會(huì)訪問太快會(huì)被禁止的
          ????response?=?requests.get(url,headers=self.headers)
          ????text?=?response.content
          ????#開始解析
          ????html?=?etree.HTML(text)
          ????target_images?=?html.xpath('//div[@id="post_content"]//p//img/@src')
          ????print(target_images)
          ????break

          部分結(jié)果如下:

          ['http://wx1.sinaimg.cn/mw690/6a04b428ly1g19akwia0rg209b09qwgf.gif',?'http://wx1.sinaimg.cn/mw690/6a04b428ly1g19al1td90g209q08sq4i.gif',....]

          好的,我們僅僅剩最后一步,下載圖片,這里我給出兩者方式:

          方式一:使用urllib庫里的urlretrieve()函數(shù),代碼如下:

          #該段代碼添加至獲得target_images后面
          #大家使用這個(gè)方法的話,一定要記得導(dǎo)入庫:from urllib import request
          for?image_url?in?target_images:
          ????request.urlretrieve(image_url,'./info/test.gif')
          ????break

          方式二:獲取鏈接的源代碼后保存至本地,代碼如下:

          #該段代碼添加至獲得target_images后面
          for?image_url?in?target_images:
          ????response?=?requests.get(image_url,headers=self.headers)
          ????f?=?open('./info/test.gif','wb')
          ????f.write(response.content)
          ????f.close()
          ????break

          兩者的結(jié)果都如下:



          ok,到此處,恭喜大家,已經(jīng)完成了99%的任務(wù)了。下面就是完善和補(bǔ)充一些代碼了。

          此函數(shù)完整代碼如下:

          def?get_target_images(self,target_urls):
          ????for?url?in?target_urls:
          ????response?=?requests.get(url,headers=self.headers)
          ????time.sleep(2)
          ????response?=?requests.get(url,headers=self.headers)
          ????text?=?response.content
          ????html?=?etree.HTML(text)
          ????target_images?=html.xpath('//div[@id="post_content"]//p//img/@src')
          ????for?image_url?in?target_images:
          ????????request.urlretrieve(image_url,'./info/test.gif')
          ????????break
          ????break
          ????#建議大家測試的時(shí)候,加上break,如果有基礎(chǔ)的可以考慮代理或者多線程

          5.第五步優(yōu)化與完善:

          一個(gè)優(yōu)秀的人,總是想寫出點(diǎn)優(yōu)秀的代碼,所以優(yōu)化必不可少

          1.優(yōu)化角度一:文件存儲(chǔ)的優(yōu)化:

          首先,上面我在這個(gè)py文件下面創(chuàng)建了一個(gè)info文件夾,所以才能寫"./info/..."這樣的代碼,但是我相信大家的目錄下肯定沒有。所以必須優(yōu)化。

          其次,我們可以這樣考慮:使用os模塊自動(dòng)創(chuàng)建一個(gè)images的文件夾,其次可以在獲取圖片集合的url時(shí)順便獲取每個(gè)圖片集合的標(biāo)題,所以開始改寫代碼:

          修改完成后如下(只需修改第二個(gè)函數(shù)):

          def?get_target_images(self,target_urls):
          ????os.mkdir('./images')
          ????for?url?in?target_urls:
          ????response?=?requests.get(url,headers=self.headers)
          ????time.sleep(2)
          ????response?=?requests.get(url,headers=self.headers)
          ????text?=?response.content
          ????html?=?etree.HTML(text)
          ????target_images?=?html.xpath('//div[@id="post_content"]//p//img/@src')
          ????title?=?html.xpath('//div[@id="post_content"]//p//img/@title')[0]
          ????os.mkdir('./images/'+title)
          ????for?index,image_url?in?enumerate(target_images):
          ????????response?=?requests.get(image_url,?headers=self.headers)
          ????????#這里我是用文件方式下載,因?yàn)椴恢罏槭裁次疫\(yùn)行urlretrieve下載時(shí)下太久了
          ????????f?=?open('./images/%s/%s.gif'%(title,index),?'wb')
          ????????f.write(response.content)
          ????????f.close()
          ????break

          示例結(jié)果;


          2.優(yōu)化角度二:速度優(yōu)化:

          我相信如果直接去掉break去爬取所有的肯定會(huì)報(bào)錯(cuò),因?yàn)樵L問太快了,所以可以采取一定的優(yōu)化手段去優(yōu)化它,這里我推薦兩種方式,第一種是多線程,第二種是代理。這里我就不給出如何實(shí)現(xiàn)這種優(yōu)化了,因?yàn)檫@篇文章的目的不在于此。

          3.優(yōu)化角度三:代碼本身優(yōu)化:

          這里第二個(gè)函數(shù)的代碼其實(shí)有點(diǎn)長了,因?yàn)槔锩嬗袃蓚€(gè)循環(huán)。所以可以考慮將其中的每一個(gè)循環(huán)封裝為一個(gè)新的函數(shù)。這個(gè)結(jié)果我將給在最后的全部代碼里面。

          4.優(yōu)化角度四:異常捕獲:

          想要捕獲異常,有簡單的方式,也有復(fù)雜的方式。下面只給出簡單方式的代碼:

          這里我們只需修改主函數(shù):

          def?run(self):
          ????try:
          ????????#首先我們需要一個(gè)函數(shù)獲取每一個(gè)url
          ????????target_urls?=?self.get_target_urls()
          ????????#其次我們需要去獲取每一個(gè)url里面的圖片
          ????????self.get_target_images(target_urls)
          ????except?Exception?as?e:
          ????????print('錯(cuò)誤原因:',e)

          復(fù)雜的方式就是分別去獲取一些常見的異常,如404或者其他異常。

          5.完善代碼:

          下面給出如何爬取多頁的思路:

          首先我們需要提取出第一、二、三頁的url,如下:

          第一頁:http://www.bbsnet.com/doutu

          第二頁:http://www.bbsnet.com/doutu/page/2

          第三頁:http://www.bbsnet.com/doutu/page/3

          好的,下面提出共同的部分:http://www.bbsnet.com/doutu/page/ + 頁數(shù)

          這里為了驗(yàn)證上面對于第一頁這個(gè)特殊頁是否適用,訪問http://www.bbsnet.com/doutu/page/1,結(jié)果可以成功訪問,因此下面我們只需去一個(gè)個(gè)迭代即可獲取一頁頁的圖片。

          代碼我將給在整體代碼中。

          三、全部代碼:

          #?-*-?coding:utf-8?-*-
          #?Author:?自學(xué)小白菜
          '''
          既然選擇了前進(jìn),那每一步都要認(rèn)真的去做
          '''


          #導(dǎo)包
          from?lxml?import?etree
          import?requests
          from?urllib?import?request
          import?time
          import?os

          class?MySpider(object):
          ????def?__init__(self):
          ????????#顯然我們需要最基礎(chǔ)的headers信息
          ????????self.headers?=?{
          ????????????'User-Agent':'Mozilla/5.0?(Windows?NT?10.0;?Win64;?x64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/86.0.4240.75?Safari/537.36',
          ????????}
          ????????#其次我們需要url
          ????????self.url?=?'http://www.bbsnet.com/doutu/page/{page}'

          ????def?run(self):
          ????????try:
          ????????????pages?=?int(input('請輸入需要獲取多少頁:'))
          ????????????for?page?in?range(1,pages+1):
          ????????????????url?=?self.url.format(page?=?page)
          ????????????????#首先我們需要一個(gè)函數(shù)獲取每一個(gè)url
          ????????????????target_urls?=?self.get_target_urls(url)
          ????????????????#其次我們需要去獲取每一個(gè)url里面的圖片
          ????????????????self.get_target_images(target_urls)
          ????????except?Exception?as?e:
          ????????????print('錯(cuò)誤原因:',e)

          ????def?get_target_urls(self,url):
          ????????'''這里我們使用一個(gè)東西,比如列表等來存儲(chǔ)url的結(jié)果并返回'''
          ????????response?=?requests.get(url,headers=self.headers)
          ????????text?=?response.content
          ????????#下面開始解析
          ????????html?=?etree.HTML(text)
          ????????target_urls?=?html.xpath('//h2/a/@href')
          ????????return?target_urls

          ????def?get_target_images(self,target_urls):
          ????????'''這里我們需要接收之前獲取的url,所以需要一個(gè)參數(shù)'''
          ????????os.mkdir('./images')
          ????????for?url?in?target_urls:
          ????????????target_images,title?=?self.get_info(url)
          ????????????for?index,image_url?in?enumerate(target_images):
          ????????????????self.download(image_url,index,title)
          ????????????????break
          ????????????break

          ????def?get_info(self,url):
          ????????response?=?requests.get(url,?headers=self.headers)
          ????????time.sleep(2)
          ????????response?=?requests.get(url,?headers=self.headers)
          ????????text?=?response.content
          ????????#?開始解析
          ????????html?=?etree.HTML(text)
          ????????target_images?=?html.xpath('//div[@id="post_content"]//p//img/@src')
          ????????title?=?html.xpath('//div[@id="post_content"]//p//img/@title')[0]
          ????????os.mkdir('./images/'?+?title)

          ????????return?target_images,title

          ????def?download(self,image_url,index,title):
          ????????response?=?requests.get(image_url,?headers=self.headers)
          ????????f?=?open('./images/%s/%s.gif'?%?(title,?index),?'wb')
          ????????f.write(response.content)
          ????????f.close()

          if?__name__?==?'__main__':
          ????spider?=?MySpider()
          ????spider.run()

          瀏覽 72
          點(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>
                  男女噼啪网站 | 日韩久久久性爱 | 91成人免费电影片 | 大香蕉伊在视频 | 中国一级黄色 |