2020年9月12日星期六

56 《零基礎入門學習Python》筆記 第056講:論一隻爬蟲的自我修養4:網絡爬圖

《零基礎入門學習Python》筆記    第056講:論一隻爬蟲的自我修養4:網絡爬圖


今天我們結合前面學習的知識,進行一個實例,從網絡上下載圖片,話說我們平時閒來無事會上煎蛋網看看新鮮事,那麼,熟悉煎蛋網的朋友一定知道,這裡有一個隨手拍的欄目,我們今天就來寫一個爬蟲,自動抓取每天更新的隨手拍。
要寫爬蟲,首先要做的第一件事就是踩點,主動發現網頁之間的規律,還有圖片鏈接之間有什麼規律,例如說,該網站的鏈接形式為:http://jandan.net /ooxx/page-' 頁碼數 '#comments,(頁碼數應該小於等於當天的頁碼數(即目前最大頁碼數)),
1.那我們怎樣獲取目前最大的頁碼數呢(最新頁碼),我們在頁碼[77]這個位置點擊右鍵,審查元素,看到了:<span class="current-comment-page">[77]< /span>
我們完全可以通過搜索  current-comment-page 在後面偏移3位就可以得到77這個最新的頁面,因為你不能去輸入一個具體的數字,因為這裡的數字每天都會改變。
2.我們在圖片的位置點擊右鍵,審查元素,發現了圖片的地址,都是來自於新浪,然後都在img 標籤裡,我們就可以使用img src 作為關鍵詞來進行查找,搜索到了圖片的地址就可以參照我們之前下載一隻貓的例子了。把下面圖片的地址用urlopen() 打開,然後將其save 到一個文件裡去(二進制),就可以了。
<img src="http://ww3.sinaimg.cn/mw600/006XNEY7gy1fy62ba9d6cj30u00u0x6p.jpg" style="max-width: 480px; max-height: 750px;">
我們弄清楚了以上幾點,就可以開始寫我們的爬蟲程序啦.....
(我們抓取前10頁的圖片,保存到指定的本地文件夾中)
下面是老師講的代碼:
  1. #从煎蛋网的随手拍栏目下载图片
  2. import urllib.request
  3. import os
  4. import random
  5. def url_open(url):
  6. req = urllib.request.Request(url)
  7. req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36')
  8. #使用代理(就加入下面五行)
  9. #proxies = ['119.6.144.70:81', '111.1.36.9:80', '203.144.144.162:8080']
  10. #proxy = random.choice(proxies)
  11. #proxy_support = urllib.request.ProxyHandler({'http':proxy})
  12. #opener = urllib.request.build_opener(proxy_support)
  13. #urllib.request.install_opener(opener)
  14. response = urllib.request.urlopen(url)
  15. html = response.read()
  16. return html
  17. def get_page(url): #得到最新页面的页码数
  18. html = url_open(url)
  19. html = html.decode('utf-8') #因为要以字符串的形式查找,所以要 decode
  20. #然后就是查找 html 中的 'current-comment-page'
  21. a = html.find( 'current-comment-page') + 23 #加上 23 位偏移就刚到到页码数的第一位数字
  22. b = html.find(']', a) #找到 a 位置之后的第一个方括号所在位置的索引坐标
  23. return html[a : b] #这就是最新的页码数啦
  24. def find_imgs(url): #给一个页面的链接,返回所有图片地址组成的列表
  25. html = url_open(url).decode('utf-8')
  26. img_addrs = [] #声明一个保存图片地址的列表
  27. #查找图片地址
  28. a = html.find('img src=')
  29. while a != -1:
  30. b = html.find('.jpg', a, a+255) #在 a 到 a+255 区间找 '.jpg',防止有不是 '.jpg' 格式的图片
  31. #如果 b 找不到,b 就返回 -1
  32. if b != -1:
  33. img_addrs.append(html[a+9: b+4])
  34. else:
  35. b = a + 9
  36. a = html.find('img src=', b)
  37. return img_addrs
  38. def save_imgs(folder, img_addrs):
  39. for each in img_addrs:
  40. filename = each.split('/')[-1]
  41. with open(filename, 'wb') as f:
  42. img = url_open(each)
  43. f.write(img)
  44. def download_figures(folder = 'figures', page = 10):
  45. os.mkdir(folder) #创建文件夹
  46. os.chdir(folder)
  47. url = "http://jandan.net/ooxx/" #随手拍栏目的链接,也是最新页面的链接
  48. page_num = int(get_page(url)) #得到最新页面的页码数
  49. for i in range(page):
  50. page_url = url + 'page-' + str(page_num) + '#comments' #得到要爬取的页面的链接
  51. print(page_url)
  52. img_addrs = find_imgs(page_url) #得到页面所有图片的地址,保存为列表
  53. save_imgs(folder, img_addrs) #保存图片到本地文件夹
  54. page_num -= 1 #逐步找到前几个页面
  55. if __name__ == '__main__':
  56. download_figures()
但是現在,煎蛋網用這段代碼是無法實現的了,主要問題在於沒有辦法爬取到.jpg,這是因為這個網站已經被加密了。
怎樣判斷一個網站被加密了,就是

使用urllib.urlopen導出html文本和審查元素中相應字段對不上。

以後你會發現對不上是常態,一般是JS加密的 可以說大一點的網站這些信息都會對不上。
那怎麼解決呢?
目前我只用的一種方法就是:使用selenium爬取js加密的網頁
需要詳細講解的可以查看:python使用selenium爬取js加密的網頁
所以呢,我的代碼就是下面這樣子了:
  1. #从加密的煎蛋网的随手拍栏目下载图片
  2. import os
  3. from selenium import webdriver
  4. import urllib.request
  5. def url_open(url): #返回普通不加密网页的源码(速度快)
  6. req = urllib.request.Request(url)
  7. req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36')
  8. response = urllib.request.urlopen(url)
  9. html = response.read()
  10. return html
  11. def url_open_jm(url): #返回加密网页的源码(速度慢)
  12. chrome = webdriver.Chrome()
  13. chrome.get(url)
  14. html = chrome.page_source
  15. return html #返回的就是字符串
  16. '''
  17. def get_page(url): #得到最新页面的页码数(可以使用不加密读码得到,为了加快速度)
  18. html = url_open(url)
  19. #然后就是查找 html 中的 'current-comment-page'
  20. a = html.find( 'current-comment-page') + 23 #加上 23 位偏移就刚到到页码数的第一位数字
  21. b = html.find(']', a) #找到 a 位置之后的第一个方括号所在位置的索引坐标
  22. return html[a : b] #这就是最新的页码数啦
  23. '''
  24. def get_page(url): #得到最新页面的页码数
  25. html = url_open(url)
  26. html = html.decode('utf-8') #因为要以字符串的形式查找,所以要 decode
  27. #然后就是查找 html 中的 'current-comment-page'
  28. a = html.find( 'current-comment-page') + 23 #加上 23 位偏移就刚到到页码数的第一位数字
  29. b = html.find(']', a) #找到 a 位置之后的第一个方括号所在位置的索引坐标
  30. return html[a : b] #这就是最新的页码数啦
  31. def find_imgs(url): #给一个页面的链接,返回所有图片地址组成的列表
  32. html = url_open_jm(url) #这个必须使用加密打开的方式
  33. img_addrs = [] #声明一个保存图片地址的列表
  34. #查找图片地址
  35. #加密的网页破解后得到的图像在这里:
  36. #<img src="http://ww3.sinaimg.cn/mw600/006XNEY7gy1fy66dacugfj30qh0zkdhu.jpg"
  37. #所以要先找jpg,然后找img src=
  38. a = html.find('.jpg')
  39. while a != -1:
  40. b = html.rfind('img src=', a-100, a) #在 a-100 到 a区间找 'img src=',必须反向查找
  41. #如果 b 找不到,b 就返回 -1
  42. if b != -1:
  43. img_addrs.append(html[b+9: a+4])
  44. a = html.find('.jpg', a+4)
  45. for each in img_addrs:
  46. print(each)
  47. return img_addrs
  48. def save_imgs(folder, img_addrs):
  49. for each in img_addrs:
  50. filename = each.split('/')[-1]
  51. with open(filename, 'wb') as f:
  52. img = url_open(each)
  53. f.write(img)
  54. def download_figures(folder = 'figures', page = 2):
  55. os.mkdir(folder) #创建文件夹
  56. os.chdir(folder)
  57. url = "http://jandan.net/ooxx/" #随手拍栏目的链接,也是最新页面的链接
  58. page_num = int(get_page(url)) #得到最新页面的页码数
  59. for i in range(page):
  60. page_url = url + 'page-' + str(page_num) + '#comments' #得到要爬取的页面的链接
  61. print(page_url)
  62. img_addrs = find_imgs(page_url) #得到页面所有图片的地址,保存为列表
  63. save_imgs(folder, img_addrs) #保存图片到本地文件夹
  64. page_num -= 1 #逐步找到前几个页面
  65. if __name__ == '__main__':
  66. download_figures()

完美實現目標,只不過selenium 的速度是真的慢,以後如果有更好的辦法,會繼續改進的,也希望大家多多批評指導。

0 留言:

發佈留言