Python3 大型網路爬蟲實戰 003 — scrapy 大型靜態圖片網站爬蟲專案實戰 — 實戰:爬取 169美女圖片網 高清圖片
原博文連結:http://www.aobosir.com/blog/2016/12/26/python3-large-web-crawler-169bb-com-HD-beautiful-pictures/
開發環境
- Python第三方庫:lxml、Twisted、pywin32、scrapy
- Python 版本:python-3.5.0-amd64
- PyCharm軟體版本:pycharm-professional-2016.1.4
- 電腦系統:Windows 10 64位
如果你還沒有搭建好開發環境,請到這篇部落格。
- 本篇部落格原始碼GitHub裡:這裡。
這一篇部落格的目的是爬取 169美女圖片網 裡面的所有的“西洋美女”的高清圖片。
爬蟲程式設計思路:
1 . 先得到 http://www.169bb.com/xiyangmeinv/ 頁面裡面所有的照片後面對應的URL網頁連結(如)。
2 . 接著在得到的URL連結網頁裡面得到裡面所有高清圖片的下載地址,進行下載。
3 . 得到所有 “西洋美女” 網頁的頁數。
觀察網頁 和 網頁原始碼
1 . 開啟 169美女圖片網:http://www.169bb.com/
2 . 我們的目的是爬取這個站點裡面所有 “西洋美女” 的高清圖片。所以點選進入“西洋美女” 標籤裡。(http://www.169bb.com/xiyangmeinv/)
3 . 觀察這個頁面,在頁面最下面,顯示了,當前一共311頁。
4 . 我們再來觀察每頁的網址有什麼共同點,我們發現:第2頁的網站是:http://www.169bb.com/xiyangmeinv/list_4_2.html;第3頁的網址是:http://www.169bb.com/xiyangmeinv/list_4_3.html;而第1頁的網站是:http://www.169bb.com/xiyangmeinv/list_4_1.html
這樣每頁的網址是有規律的,按照這個規律,我們可以推測出“西洋美女” 的第120頁的網址就應該是:http://www.169bb.com/xiyangmeinv/list_4_120.html。事實的確是這樣的。好。
5 . 現在,我們隨便點選一個圖片,進去看看這個美女的高清圖片集。
裡面都是高清的圖片,並且有很多,並且,不止一頁。就我隨機點選的這個美女的連結就有11頁,並且一頁裡面有5張左右的高清圖片。
6 . 並且它的每頁的網址也是有規律的。
第2頁是:http://www.169bb.com/xiyangmeinv/2016/1117/37333_2.html
第3頁是:http://www.169bb.com/xiyangmeinv/2016/1117/37333_3.html
第1頁是:http://www.169bb.com/xiyangmeinv/2016/1117/37333.html
…
但是有的美女的網址裡只有一頁,比如這個:http://www.169bb.com/xiyangmeinv/2016/0103/5974.html
好了,現在這個目標網頁,我們已經分析完了。現在就可以程式設計。
寫程式
原始碼GitHub裡:這裡。
接下來我們為大家講解大型圖片爬蟲專案編寫實戰。
Step 1 .
建立一個Scrapy爬蟲專案:
scrapy startproject secondDemo
建立一個scrapy爬蟲檔案,我們就在這個檔案裡面寫爬取目標網站裡面圖片的爬蟲程式。
cd secondDemo
scrapy genspider -t basic pic_169bb 169bb.com
用 PyCharm 軟體開啟剛剛建立的 secondDemo
工程。
Step 2 . 在 items.py
檔案裡面的SeconddemoItem()
函式裡面建立一個物件,這個物件在其他的檔案裡面會使用到。
Step 3 . 現在開始爬蟲的編寫。進入pic_169bb.py
檔案。
爬蟲(pic_169bb.py
檔案)會自動的先爬首頁(http://169bb.com/),爬完首頁之後,會自動的進入parse()
回撥函式。
這個回撥函式中,我們需要寫些東西。
先獲取所有欄目的名字和地址。
檢視原始碼:
在pic_169bb.py
檔案中的 parse()
回撥函式中新增下面的程式碼:
urldata = response.xpath("/html/body/div[@class='header']/div[@class='hd_nav']/div[@class='w1000']//a/@href").extract()
print(urldata)
現在執行一下,輸出:
繼續進行下一次的爬取:
先匯入一個模組
from scrapy.http import Request
爬取子欄目的第一頁,即西洋美女網址的第一頁。
xiyangurldata = urldata[4] # 獲取西洋美女首頁網址
print(xiyangurldata)
yield Request(url=xiyangurldata, callback=self.next)
def next(self, response):
pass
def next(self, response):
page_title_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@alt").extract()
print(page_title_list)
page_url_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@href").extract()
print(page_url_list)
pass
執行輸出一下:
page_num = response.xpath("//span[@class='pageinfo']//strong/text()").extract()[0] # 得到西洋美女總頁數
print(page_num)
print(response.url)
for i in range(1, int(page_num)+1):
page_url = response.url + 'list_4_'+ str(i) + '.html' # 得到西洋美女每一個頁面的網址
print(page_url)
pass
執行輸出一下:
繼續下一次:
for i in range(1, int(page_num)+1):
page_url = response.url + 'list_4_'+ str(i) + '.html' # 得到西洋美女每一個頁面的網址
print(page_url)
yield Request(url=page_url, callback=self.next2)
pass
def next2(self, response):
pass
現在獲取每一個美女的網頁網址:
def next2(self, response):
page_title_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@alt").extract()
# print(page_title_list)
page_url_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@href").extract()
# print(page_url_list)
for i in range(0, len(page_url_list)):
gril_page_url = page_url_list[i]
print(gril_page_url)
yield Request(url=gril_page_url, callback=self.next3)
pass
def next3(self, response):
pass
執行程式看看:
next3()
這個回撥函式的功能就是得到一個美女網頁裡面的所有的頁面的網址。
有的美女的網頁裡面只有一個頁面,有的美女的網頁裡面有多個頁面:
可以統一解決。
測試:
輸出:
同樣的回撥函式
輸出:
所以,我們可以這樣寫程式:
當得到的頁碼為-3,說明這個美女的網頁是單頁的;如果得到的頁碼數不等於-3,說明這個美女的網頁是多也的。
測試程式:
對於多頁面的美女網頁網址
執行輸出:
D:\WorkSpace\python_ws\python-large-web-crawler\secondDemo>scrapy crawl pic_169bb --nolog
10
http://www.169bb.com/xiyangmeinv/2016/0717/36463.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_5.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_10.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_9.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_6.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_8.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_7.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_3.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_4.html
http://www.169bb.com/xiyangmeinv/2016/0717/36463_2.html
D:\WorkSpace\python_ws\python-large-web-crawler\secondDemo>
對於單頁面的美女網頁:
def parse(self, response):
...
yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.demo)
回撥函輸一樣。
執行輸出:
D:\WorkSpace\python_ws\python-large-web-crawler\secondDemo>scrapy crawl pic_169bb --nolog
-3
http://www.169bb.com/xiyangmeinv/2016/0103/2268.html
D:\WorkSpace\python_ws\python-large-web-crawler\secondDemo>
成功。
所以現在的爬蟲程式碼應該是這樣的:
# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request
class Pic169bbSpider(scrapy.Spider):
name = "pic_169bb"
allowed_domains = ["169bb.com"]
start_urls = ['http://169bb.com/']
def parse(self, response):
title_list = response.xpath("/html/body/div[@class='header']/div[@class='hd_nav']/div[@class='w1000']//a/text()").extract()
# print(title_list)
urldata = response.xpath("/html/body/div[@class='header']/div[@class='hd_nav']/div[@class='w1000']//a/@href").extract()
#print(urldata)
xiyang_title = title_list[4] # 獲取西洋美女標籤的文字內容
xiyang_urldata = urldata[4] # 獲取西洋美女首頁網址
# print(xiyang_title, xiyang_urldata)
yield Request(url=xiyang_urldata, callback=self.next)
# yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0717/36463.html', callback=self.demo)
# yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.demo)
def next(self, response):
page_num_str = response.xpath("//span[@class='pageinfo']//strong/text()").extract()[0] # 得到西洋美女總頁數
# print(page_num_str)
# print(response.url)
for i in range(1, int(page_num_str)+1):
page_url = response.url + 'list_4_'+ str(i) + '.html' # 得到西洋美女每一個頁面的網址
# print(page_url)
yield Request(url=page_url, callback=self.next2)
pass
def next2(self, response):
page_title_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@alt").extract()
# print(page_title_list)
page_url_list = response.xpath("/html/body//div[@class='w1000 box03']/ul[@class='product01']//li/a/@href").extract()
# print(page_url_list)
for i in range(0, len(page_url_list)):
gril_page_url = page_url_list[i] # 得到西洋美女頁面裡面每一個美女的網頁網址
print(gril_page_url)
yield Request(url=gril_page_url, callback=self.next3)
pass
def next3(self, response):
rela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()
pages_num = len(rela_pages_list) - 3
# print(pages_num)
self.getPic(response)
if pages_num == -3:
# pages_num = 1
return
for i in range(2, pages_num+1):
girl_page_url = response.url.replace('.html', '_') + str(i) + '.html'
# print(girl_page_url)
yield Request(url=girl_page_url, callback=self.next4)
pass
# def demo(self, response):
# # rela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()
# # pages_num = len(rela_pages_list)-3
# # print(pages_num)
# # pass
# rela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()
# pages_num = len(rela_pages_list) - 3
# # print(pages_num)
# self.getPic(response)
# if pages_num == -3:
# # pages_num = 1
# return
# for i in range(2, pages_num+1):
# girl_page_url = response.url.replace('.html', '_') + str(i) + '.html'
# # print(girl_page_url)
# yield Request(url=girl_page_url, callback=self.next4)
# pass
def next4(self, response):
self.getPic(response)
pass
def getPic(self, response):
print(response.url)
pass
現在,我們需要在getPic()
函式中獲取每一個美女網頁的每一個頁面裡面的所有高清圖片。
def getPic(self, response):
# print(response.url)
item = SeconddemoItem()
item['url'] = response.xpath("//div[@class='big-pic']/div[@class='big_img']//p/img/@src").extract()
print(item['url'])
pass
測試執行:
測試多頁的美女網頁:
先將parse()
函式的最後一行改為:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0717/36463.html', callback=self.demo)
測試單頁的美女網頁:
將parse()
函式的最後一行改為:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.demo)
成功。
下載高清圖片
OK,現在我們就已經得到了所有西洋美女的所有高清圖片的下載地址,我們在piplines.py
檔案中使用它們。
刪除了next4()
回撥函式。在demo()
回撥函式裡面呼叫的都是getPic()
回撥函式。
def demo(self, response):
# rela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()
# pages_num = len(rela_pages_list)-3
# print(pages_num)
# pass
rela_pages_list = response.xpath("//div[@class='dede_pages']/ul//li/a/text()").extract()
pages_num = len(rela_pages_list) - 3
# print(pages_num)
self.getPic(response)
if pages_num == -3:
# pages_num = 1
return
for i in range(2, pages_num+1):
girl_page_url = response.url.replace('.html', '_') + str(i) + '.html'
# print(girl_page_url)
yield Request(url=girl_page_url, callback=self.getPic)
pass
# error : yield 經過了一箇中間函式,執行就有問題。我現在還不知道為什麼
# def next4(self, response):
# self.getPic(response)
# pass
並將getPic()
函式裡面的item寫到生成器裡面:
def getPic(self, response):
# print(response.url)
item = SeconddemoItem()
item['url'] = response.xpath("//div[@class='big-pic']/div[@class='big_img']//p/img/@src").extract()
# print(item['url'])
# pass
yield item
測試:
測試單頁的美女網頁:
將parse()
函式的最後一行改為:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.getPic)
成功。
測試多頁的美女網頁:
先將parse()
函式的最後一行改為:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0717/36463.html', callback=self.demo)
也算算成功,因為有重複的檔名,所以自動替換,所以這裡需要做修改。
我們可以使用美女圖片網址裡面的數字作為圖片檔名的固定字首來給圖片命名,使用正規表示式獲取網址的數字。
在 pipelines.py
檔案 中的 process_item()
函式中使用正規表示式得到圖片下載網址的數字:
import re
import urllib.request
class SeconddemoPipeline(object):
def process_item(self, item, spider):
# print(len(item['url']))
for i in range(0, len(item['url'])):
this_url = item['url'][i]
id = re.findall('http://724.169pp.net/169mm/(.*?).jpg', this_url)[0]
id = id.replace('/', '_')
print(id)
# file = 'D:/WorkSpace/python_ws/python-large-web-crawler/xiyangmeinv/' + str(i) + '.jpg'
# print('Downloading :' , file)
# urllib.request.urlretrieve(this_url, filename=file)
# print('Final Download :' , file)
return item
要想使用 pipelines.py
檔案 中的 SeconddemoPipeline
類,需要在 settings.py
檔案裡面設定 ITEM_PIPELINES
項:
ITEM_PIPELINES = {
'secondDemo.pipelines.SeconddemoPipeline': 300,
}
這裡,我有一件事情不懂,關於正規表示式的: 網址裡面的
.
也是正規表示式中的工具字元,也是資料中中的內容,那麼正規表示式是如何分辨它在這裡是功能字元還是內容字元?
在pic_169bb.py
檔案的demo()
回撥函式中,這樣寫才能獲取到美女網頁的第一頁的圖片地址:
# error
# self.getPic(response)
# succes 為啥將下面的程式碼用self.getPic(response)的形式不能正常的獲取到,而使用下面的程式碼卻能獲取到?
item = SeconddemoItem()
item['url'] = response.xpath("//div[@class='big-pic']/div[@class='big_img']//p/img/@src").extract()
# print(item['url'])
# pass
yield item
執行程式試試:
測試單頁的美女網頁:
將parse()
函式的最後一行改為:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0103/2268.html', callback=self.getPic)
成功。
測試多頁的美女網頁:
先將parse()
函式的最後一行改為:yield Request(url='http://www.169bb.com/xiyangmeinv/2016/0717/36463.html', callback=self.demo)
都成功。
先測試下載圖片:
將 pipelines.py
檔案 中的 SeconddemoPipeline
類的process_item()
函式裡面,新增程式碼:
def process_item(self, item, spider):
# print(len(item['url']))
for i in range(0, len(item['url'])):
this_url = item['url'][i]
id = re.findall('http://724.169pp.net/169mm/(.*?).jpg', this_url)[0]
id = id.replace('/', '_')
# print(id)
file = 'D:/WorkSpace/python_ws/python-large-web-crawler/xiyangmeinv/' + id + '.jpg'
print('Downloading :' , file)
urllib.request.urlretrieve(this_url, filename=file)
print('Final Download :' , file)
return item
執行程式,沒有毛病:(除了下載速度有點慢)
下載 169美女圖片網 的所有西洋美女的圖片
在 pic_169bb.py
檔案裡, 將parse()
函式的最後一行改為:yield Request(url=xiyang_urldata, callback=self.next)
將 demo()
函式裡面的所有程式碼複製一份到 next3()
函式裡:
現在,執行程式:(最終的程式)
成功!
防反爬技術
Step 4 . 不遵循 robots.txt
協議。
將 settings.py
檔案裡面的 ROBOTSTXT_OBEY
項設定為:False
Step 6 . 模仿瀏覽器
請先檢視這篇部落格:http://blog.csdn.net/github_35160620/article/details/52489709 裡面是:六 . 設定 使用者代理(user_agent)。
將 settings.py
檔案裡面的 USER_AGENT
項設定為:瀏覽器的使用者代理資訊。
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.22 Safari/537.36 SE 2.X MetaSr 1.0'
Step 7 . 禁止快取
將 settings.py
檔案裡面的 COOKIES_ENABLED
項設定為:False
。
COOKIES_ENABLED = False
搞定
需要升級的地方:(2016-11-27 19:34:34)
- 在易錯的程式碼段加上異常檢測程式
- 在下載圖片的程式碼加上:超時異常檢測程式
- 記錄成功下載的、超時失敗下載的、連結失敗下載的 資訊
- 新增斷點續下功能。
相關文章
- Python3 大型網路爬蟲實戰 004 — scrapy 大型靜態商城網站爬蟲專案編寫及資料寫入資料庫實戰 — 實戰:爬取淘寶Python爬蟲網站資料庫
- 大型商城網站爬蟲專案實戰網站爬蟲
- Python3 大型網路爬蟲實戰 — 給 scrapy 爬蟲專案設定為防反爬Python爬蟲
- ReactPHP 爬蟲實戰:下載整個網站的圖片ReactPHP爬蟲網站
- Python爬蟲實戰詳解:爬取圖片之家Python爬蟲
- 網路爬蟲——爬蟲實戰(一)爬蟲
- Python大型網路爬蟲專案開發實戰(全套)Python爬蟲
- 圖片爬取實戰一
- Python爬蟲—爬取某網站圖片Python爬蟲網站
- node:爬蟲爬取網頁圖片爬蟲網頁
- 爬蟲---xpath解析(爬取美女圖片)爬蟲
- 網路爬蟲---從千圖網爬取圖片到本地爬蟲
- Python靜態網頁爬蟲專案實戰Python網頁爬蟲
- python3網路爬蟲開發實戰_Python3 爬蟲實戰Python爬蟲
- 網路爬蟲(六):實戰爬蟲
- 爬蟲 Scrapy框架 爬取圖蟲圖片並下載爬蟲框架
- 爬蟲實戰scrapy爬蟲
- python爬蟲---網頁爬蟲,圖片爬蟲,文章爬蟲,Python爬蟲爬取新聞網站新聞Python爬蟲網頁網站
- Python3 大型網路爬蟲實戰 002 --- scrapy 爬蟲專案的建立及爬蟲的建立 --- 例項:爬取百度標題和CSDN部落格Python爬蟲
- 《Python3網路爬蟲開發實戰》教程||爬蟲教程Python爬蟲
- Python網路爬蟲實戰小專案Python爬蟲
- Python網路爬蟲實戰專案大全!Python爬蟲
- Python網路爬蟲實戰Python爬蟲
- 網路爬蟲——專案實戰(爬取糗事百科所有文章)爬蟲
- [Python3網路爬蟲開發實戰] 分散式爬蟲原理Python爬蟲分散式
- Python爬蟲入門-爬取pexels高清圖片Python爬蟲
- Python3 大型網路爬蟲實戰 001 --- 搭建開發環境Python爬蟲開發環境
- Python3網路爬蟲開發實戰Python爬蟲
- 【python--爬蟲】千圖網高清背景圖片爬蟲Python爬蟲
- Java爬蟲批量爬取圖片Java爬蟲
- 簡單的爬蟲:爬取網站內容正文與圖片爬蟲網站
- Python網路爬蟲實戰專案大全 32個Python爬蟲專案demoPython爬蟲
- python3網路爬蟲開發實戰pdfPython爬蟲
- python3網路爬蟲開發實戰_Python 3開發網路爬蟲(一)Python爬蟲
- 自學python網路爬蟲,從小白快速成長,分別實現靜態網頁爬取,下載meiztu中圖片;動態網頁爬取,下載burberry官網所有當季新品圖片。Python爬蟲網頁
- 爬蟲專案實戰(一)爬蟲
- 爬蟲實戰專案集合爬蟲
- 爬蟲實戰專案合集爬蟲