歡迎關注我的公衆號「測試遊記」
由於想要了解一下友商的產品信息,所以簡單的寫一下爬取他們信息的爬蟲
創建項目
$ scrapy startproject Dahua
$ cd Dahua
$ scrapy genspider dahua dahuatech.com
使用
scrapy
腳手架創建一個項目進入項目路徑
創建一個名叫
dahua
的爬蟲,它的爬取範圍是dahuatech.com
域名下
分析爬取內容
產品類別url地址爲:http://www.dahuatech.com/product.html
所以修改開始的url start_urls
class DahuaSpider(scrapy.Spider):
name = 'dahua' # 爬蟲名稱
allowed_domains = ['dahuatech.com'] # 允許爬取域名
start_urls = ['https://www.dahuatech.com/product.html'] # 請求的第一個url
def parse(self, response):
pass
需要爬取的爲設備的具體信息
產品詳情地址
產品名稱
產品描述
產品概述
技術參數
尺寸圖
訂貨型號
所以先在 Dahua/items.py
寫上
import scrapy
class DahuaItem(scrapy.Item):
url = scrapy.Field() # 產品詳情地址
product_name = scrapy.Field() # 產品名稱
product_description = scrapy.Field() # 產品描述
product_overview = scrapy.Field() # 產品概述
technical_parameter = scrapy.Field() # 技術參數
dimension_drawing = scrapy.Field() # 尺寸圖
order_type = scrapy.Field() # 訂貨型號
獲取設備類型列表
從第一個頁面可以看出,設備分成了很多大類,大類中又有很多的小類
所以我們先拿到全部小類的url地址
使用 XPathHelper
工具進行 Xpath
定位
由於我懶得解析太多Xpath,所以我取用了離要獲取的url最大層級的 div
標籤
對應的URL的Xpath爲://div[@class='product-channel-list f-cb']//a/@href
對呀的文字的Xpath爲://div[@class='product-channel-list f-cb']//a/text()
所以爬蟲中第一個解析函數 parse
def parse(self, response):
print('正在爬取全部產品類別')
url_list = response.xpath("//div[@class='product-channel-list f-cb']//a/@href").extract()
productlist_list = response.xpath("//div[@class='product-channel-list f-cb']//a/text()").extract()
productlist_list = productlist_list
for url, productlist in zip(url_list, productlist_list):
if url.startswith('http'):
yield scrapy.Request(url=url, callback=self.parse_productlist, meta={'productlist': productlist})
獲取設備列表
任意點擊一個小類進入如下頁面
包含了 設備名稱
, 描述信息
。
查看詳情
按鈕是進入設備詳情頁的
所以這兒需要獲取到3個Xpath
全部的 查看詳情
: //li//span[1]//a/@href
全部的 設備名稱
: //div[@class='product-list-b']//ul[@class='f-cb']//h3/text()
全部的 描述信息
: //div[@class='product-list-b']//ul[@class='f-cb']//a/p[1]/text()
所以代碼爲:
def parse_productlist(self, response):
print('正在爬取產品列表')
url_list = response.xpath('//li//span[1]//a/@href').extract()
product_name_list = response.xpath("//div[@class='product-list-b']//ul[@class='f-cb']//h3/text()").extract()
product_description_list = response.xpath(
"//div[@class='product-list-b']//ul[@class='f-cb']//a/p[1]/text()").extract()
for url, product_name, product_description in zip(url_list, product_name_list, product_description_list):
yield scrapy.Request(url=url, callback=self.parse_productdetail,
meta={
'productlist': response.meta['productlist'],
'product_name': product_name,
'product_description': product_description
})
page_list = response.xpath("//div[@class='news-page w1400']//a/@href").extract()
page_list = [i for i in page_list if i.startswith('http')]
if page_list:
for url in page_list:
yield scrapy.Request(url=url, callback=self.parse_productlist,
meta={'productlist': response.meta['productlist']})
往處理詳情頁的地方傳入了 product_name
和 product_description
也就是設備名稱,設備描述
由於部分頁面有多頁,所以也做了頁面的跳轉
page_list = response.xpath("//div[@class='news-page w1400']//a/@href").extract()
page_list = [i for i in page_list if i.startswith('http')]
if page_list:
for url in page_list:
yield scrapy.Request(url=url, callback=self.parse_productlist,
meta={'productlist': response.meta['productlist']})
本來這裏要處理重複頁面的,但是由於 Scrapy
自帶了緩存機制,它會跳過爬取相同的 url
,所以就這樣了~
獲取詳情頁
進入詳情頁後發現數據是動態出現的,使用抓包的方式很容易可以發現它應該ajax請求的方式刷新數據
當前頁面:https://www.dahuatech.com/product/info/93.html
ajax
請求頁面:https://www.dahuatech.com/ajax/product/93/1
其中相同的部分爲 93
由於我懶得再爬一層,所以直接用 requests
發起了 get
請求
def parse_productdetail(self, response):
print('正在爬取產品詳情')
base_url = 'https://www.dahuatech.com/ajax/product/%s/%s'
item = DahuaItem()
product_num = re.findall(r'http.*?info/(\d+).html.*?', response.url)
product_num = product_num and int(product_num[0])
# 產品詳情地址
item['url'] = response.url
# 產品名稱
item['product_name'] = response.meta['product_name']
# 產品描述
item['product_description'] = response.meta['product_description']
# 產品概述
item['product_overview'] = re.findall(r'<div class="one_content">(.*?)</div>',
requests.get(base_url % (product_num, 1)).text,
re.S | re.M)[0]
# 技術參數
item['technical_parameter'] = requests.get(base_url % (product_num, 2)).text
# 尺寸圖
item['dimension_drawing'] = re.findall(r'src=".*?"',
requests.get(base_url % (product_num, 3)).text,
re.S | re.M)[0]
# 訂貨型號
item['order_type'] = re.findall(r'>(.*?)</p',
requests.get(base_url % (product_num, 4)).text,
re.S | re.M)[0]
yield item
數據持久化
使用最簡單的數據持久化方式:寫入json
修改 Dahua/pipelines.py
import json
class DahuaPipeline(object):
def open_spider(self, spider):
self.file = open('dahua.json', 'w')
def process_item(self, item, spider):
content = json.dumps(dict(item), ensure_ascii=False) + '\n'
self.file.write(content)
return item
def close_spider(self, spider):
self.file.close()
一次爬取分爲三步:
打開
dahua.json
文件寫入內容
關閉
dahua.json
文件
修改 Dahua/settings.py
關閉君子協議
ROBOTSTXT_OBEY = False
開啓數據持久化部分
ITEM_PIPELINES = {
'Dahua.pipelines.DahuaPipeline': 300,
}
查看結果
在外部使用
$ scrapy crawl dahua