實現業務邏輯如下:
1. 創建scrapy項目,並生成 爬蟲
2. 在suning.py中實現Schedul 和 Spider業務邏輯
3. 修改start_urls為正確的初始請求地址
4. 構造parse(self,response)函數(底部封裝自動發送請求,)獲取響應
5. 根據響應,使用xpath提取大分類和中間分類的list
6. 根據上述得到的list再遍歷,使用xpath提取我們需要的內容字段,存入剛構建的空dict中
7. 如果要進入到下一個商品列表頁面,則 yield 一個Requset對象,指明要進入的url,callback,以及把item通過meta傳到列表頁響應中。
8. 構建callback對應的商品列表頁面數據提取函數 parse_book_list(self,response),使用xpath提取我們需要的內容字段,使用yield response.yellow()構造請求,指明要進入的url(使用的是follow,所以可以是不完整的url),callback,以及把item通過meta傳到詳情頁響應中。
9. 構建callback對應的商品詳情頁面數據提取函數 parse_book_detail(self,response),使用xpath提取我們需要的內容字段,字段提取完成后,就可以把item返回了,yield item。
10. 構建分類頁中的后一部分圖書列表數據請求,首先找到next_url,然后構造Request。
11. 上述最終yield 的item 通過在settings中設置spiderpiplelines,就會進入指定的spiderpiplelines中通過process_item()進行進一步數據處理,比如清洗和保存。
12. 另外在Downloader Middlewares中還可以設置open_spider(),close_spider(),做相應處理。
# 注意點,scrapy框架底層實現了多線程,所以item傳遞時,為避免數據覆蓋錯位情況,需要使用deepcopy()傳遞下去。
下面直接上代碼:
# suning.py # -*- coding: utf-8 -*- import scrapy import re from copy import deepcopy class SuningSpider(scrapy.Spider): name = 'suning' allowed_domains = ['suning.com'] start_urls = ['https://book.suning.com/'] def parse(self, response): #獲取大分類的分組 div_list = response.xpath("//div[@class='menu-list']/div[@class='menu-item']") # 和大分類呼應的中間分類組 div_sub_list = response.xpath("//div[@class='menu-list']/div[@class='menu-sub']") for div in div_list[:1]: item = {} #大分類的名字--eg:文學藝術 item["b_cate"] = div.xpath(".//h3/a/text()").extract_first() #當前大分類的所有的中間分類的位置 current_sub_div = div_sub_list[div_list.index(div)] #獲取中間分類的分組--eg: 小說,青春文學 p_list = current_sub_div.xpath(".//div[@class='submenu-left']/p[@class='submenu-item']") for p in p_list: #中間分類的名字 item["m_cate"] = p.xpath("./a/text()").extract_first() #獲取小分類的分組 li_list = p.xpath("./following-sibling::ul[1]/li") for li in li_list: #小分類的名字 item["s_cate"] = li.xpath("./a/text()").extract_first() #小分類的URL地址 item["s_href"] = li.xpath("./a/@href").extract_first() #請求圖書的列表頁 yield scrapy.Request( item["s_href"], callback=self.parse_book_list, meta={"item":deepcopy(item)} ) #發送請求,獲取列表頁第一頁后一部分的數據 next_part_url_temp = "https://list.suning.com/emall/showProductList.do?ci={}&pg=03&cp=0&il=0&iy=0&adNumber=0&n=1&ch=4&sesab=ABBAAA&id=IDENTIFYING&cc=010&paging=1&sub=0" #獲取url地址的ci ci = item["s_href"].split("-")[1] next_part_url = next_part_url_temp.format(ci) yield scrapy.Request( next_part_url, callback=self.parse_book_list, meta={"item":deepcopy(item)} ) def parse_book_list(self,response): #處理圖書列表頁內容 item = response.meta["item"] #獲取圖書列表頁的分組 # li_list = response.xpath("//div[@id='filter-results']/ul/li") li_list =response.xpath("//li[contains(@class,'product book')]") for li in li_list[:1]: #書名 item["book_name"] = li.xpath(".//p[@class='sell-point']/a/text()").extract_first().strip() #書的url地址,不完整 item["book_href"] = li.xpath(".//p[@class='sell-point']/a/@href").extract_first() #書店名 item["book_store_name"] = li.xpath(".//p[contains(@class,'seller oh no-more')]/a/text()").extract_first() #發送詳情頁的請求 yield response.follow( item["book_href"], callback = self.parse_book_detail, meta = {"item":deepcopy(item)} ) #列表頁翻頁 #前半部分數據的url地址 next_url_1 = "https://list.suning.com/emall/showProductList.do?ci={}&pg=03&cp={}&il=0&iy=0&adNumber=0&n=1&ch=4&sesab=ABBAAA&id=IDENTIFYING&cc=010" #后半部分數據的url地址 next_url_2 = "https://list.suning.com/emall/showProductList.do?ci={}&pg=03&cp={}&il=0&iy=0&adNumber=0&n=1&ch=4&sesab=ABBAAA&id=IDENTIFYING&cc=010&paging=1&sub=0" ci = item["s_href"].split("-")[1] #當前的頁碼數 current_page = re.findall('param.currentPage = "(.*?)";',response.body.decode())[0] #總的頁碼數 total_page = re.findall('param.pageNumbers = "(.*?)";',response.body.decode())[0] if int(current_page)<int(total_page): next_page_num = int(current_page) + 1 next_url_1 = next_url_1.format(ci,next_page_num) #組裝前半部分URL yield scrapy.Request( next_url_1, callback=self.parse_book_list, meta = {"item":item} ) #構造后半部分數據的請求 next_url_2 = next_url_2.format(ci,next_page_num) yield scrapy.Request( next_url_2, callback=self.parse_book_list, meta = {"item":item} ) def parse_book_detail(self,response):#處理圖書詳情頁內容 item = response.meta["item"] price_temp_url = "https://pas.suning.com/nspcsale_0_000000000{}_000000000{}_{}_10_010_0100101_226503_1000000_9017_10106____{}_{}.html" p1 = response.url.split("/")[-1].split(".")[0] p3 = response.url.split("/")[-2] p4 = re.findall('"catenIds":"(.*?)",',response.body.decode()) if len(p4)>0: p4 = p4[0] p5 = re.findall('"weight":"(.*?)",',response.body.decode())[0] price_url = price_temp_url.format(p1,p1,p3,p4,p5) yield scrapy.Request( price_url, callback=self.parse_book_pirce, meta={"item":item} ) def parse_book_pirce(self,response): #提取圖書的價格 item = response.meta["item"] # item["book_price"] = re.findall('"netPrice":"(.*?)"',response.body.decode())[0] # print(item) yield item
關於setting.py & pipeline.py & middlewares.py的代碼比較簡單,這里就不傳了。