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

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

          共 16066字,需瀏覽 33分鐘

           ·

          2020-11-05 18:41

          大家好,我是一行

          今天是小白菜同學(xué)的投稿,老規(guī)矩一個(gè)贊10積分

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

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

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

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

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

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

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

          下面開始盤它。

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

          二、分析與編寫代碼:

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

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

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

          這里我們還是采用面向?qū)ο髞?lái)寫,因?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è)東西,比如列表等來(lái)存儲(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í)候我們對(duì)于文本要decode('utf-8'),而有時(shí)候?qū)τ谖谋拘枰猟ecode('gbk'),這是根據(jù)網(wǎng)頁(yè)源代碼的編碼形式來(lái)寫的,比如這個(gè)網(wǎng)站的源代碼如下:


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

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

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

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

          于是寫下這樣代碼:

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

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


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


          下面我們使用xpath來(lái)解析這個(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ù)就完成了,是不是十分簡(jiǎn)單。該函數(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測(cè)試
              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)把我們重定向到首頁(yè),這樣我們顯然獲取不成功,于是,我們?cè)趺崔k呢?在訪問(wèn)一次就可以了,我們僅需要在加上一次請(qǐ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è)大麻煩,我們下面的工作就很簡(jiǎn)單了。


          可以得到以下內(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ì)訪問(wèn)太快會(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庫(kù)里的urlretrieve()函數(shù),代碼如下:

          #該段代碼添加至獲得target_images后面
          #大家使用這個(gè)方法的話,一定要記得導(dǎo)入庫(kù):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
              #建議大家測(cè)試的時(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/..."這樣的代碼,但是我相信大家的目錄下肯定沒(méi)有。所以必須優(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問(wèn)太快了,所以可以采取一定的優(yōu)化手段去優(yōu)化它,這里我推薦兩種方式,第一種是多線程,第二種是代理。這里我就不給出如何實(shí)現(xiàn)這種優(yōu)化了,因?yàn)檫@篇文章的目的不在于此。

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

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

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

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

          這里我們只需修改主函數(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ù)雜的方式就是分別去獲取一些常見(jiàn)的異常,如404或者其他異常。

          5.完善代碼:

          下面給出如何爬取多頁(yè)的思路:

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

          第一頁(yè):http://www.bbsnet.com/doutu

          第二頁(yè):http://www.bbsnet.com/doutu/page/2

          第三頁(yè):http://www.bbsnet.com/doutu/page/3

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

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

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

          三、全部代碼:

          # -*- 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('請(qǐng)輸入需要獲取多少頁(yè):'))
                      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è)東西,比如列表等來(lái)存儲(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()

             

          點(diǎn)標(biāo)轉(zhuǎn)

          最成功的一次抓包!我發(fā)現(xiàn)了色情版“微信”背后的秘密

          黑科技一鍵搞定雙11,提現(xiàn)提到手軟!

          點(diǎn)擊閱讀原文,積分可以免費(fèi)換書

          瀏覽 54
          點(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>
                  国产微拍精品一区 | 婷婷淫色 | 中文字幕成人乱码熟女 | 欧美黄色录像 | 狠狠操狠狠爽 |