scrapy爬蟲--蘇寧圖書


實現業務邏輯如下:

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的代碼比較簡單,這里就不傳了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM