Python爬蟲:爬取京東商品簡介

1、前言

目的

長文鉅著,本文將手摸手交你零基礎學會Python爬蟲。
文章以爬取京東網上一款Nike鞋的商品信息爲例。

關於爬蟲

爬蟲大致可以分爲三個階段

  1. 爬取網站信息
  2. 篩選出我們要的信息
  3. 持久化數據

現在很多網站也都會做一些反爬措施,比如很多網頁需要登錄纔可以查看,拿不到授權,自然就訪問不了頁面了,當然這個只要我們把用戶名、密碼一起放到請求中,並且參數名和網站的一樣就可以。所以爲了防止這種機器操作,就有了驗證碼,驗證碼有很多中,反正越難用代碼模擬,反爬的效果就越好。還有的請求過於頻繁就禁止繼續訪問,這樣也可以降低爬蟲的速度。不過此文章要爬的JD並沒有什麼限制,我們使用瀏覽器即使不登錄也是可以匿名訪問(遊客模式)的。接下來就按三個階段分別開始講述怎麼爬蟲吧。完整代碼會放到碼雲上(地址在文末)。

關於Python

Python是一門高級語言,語法簡潔,對於博主這種寫習慣了Java這門囉嗦、嚴謹的人來說,使用python確實會有點不習慣。python在爬蟲、人工智能、大數據等領域應用廣泛,這有賴於python強大的第三方庫。本此爬蟲有使用到“lxml”這個第三方庫,比起自己寫正則表達式來過濾數據方便太多了,香!

2、準備

工具

  • PyChram
  • python 3.0+

安裝第三方庫和包

- BeautifulSoup
- xlwt
- requests

包的導入在PyChram裏,只要光標移至紅色波浪線上,然後點擊圖所示
在這裏插入圖片描述
在這裏插入圖片描述

第三方庫

可以使用pip工具安裝第三方庫,pip程序在python根目錄下的Scripts文件夾下:%python%\Scripts
如果未將pip加入到環境中,在 Scripts運行cmd程序,執行以下命令即可(以管理員身份運行)
在這裏插入圖片描述

  • cmd命令如下:pip install lxml
    小學二年級學的知識點,這裏就不贅述了。

3、敲代碼

1、爬取網站信息

在爬取網站之前,我們需要先分析目標網站。以京東網站爬取Nike的A錐(AJ1)爲例爲例。首先我們需要爬到京東搜索AJ1的信息,即拿到它的HTML文本,所有我們得先知道它的url是啥。
在這裏插入圖片描述
我們先來分析這個url是怎麼發送請求,纔可以搜索到我們要的關鍵字的
https://search.jd.com/Search?keyword=AJ1&enc=utf-8&wq=AJ1&pvid=a18e7d9fc93b4cf1a44b2cb22c02fb1a

在這裏插入圖片描述
通過上面分析,我們知道,至少我需要傳keyword這個參數過去。編碼最好還是帶上
於是我們的url就是:https://search.jd.com/Search?keyword=AJ1&enc=utf-8

拿到地址後,我們就可以用python去扒它了!

import requests

if __name__ == '__main__':
    url = 'https://search.jd.com/Search?keyword=aj1&enc=utf-8'  # 目標網站地址
    response = requests.get(url)  # 請求訪問網站
    html = response.text  # 獲取網頁源碼
    print(html)  # 將源碼打印到控制檯

我們就以簡單的方式請求,然後把整個頁面的html打印到控制檯上。

在這裏插入圖片描述在這裏插入圖片描述
也就是說京東把我們的請求攔截了,但是我們在瀏覽器不用登錄也是可以訪問的,那爲什麼我們用代碼去訪問就會報錯呢?
這個其實是因爲我們使用瀏覽器方法網址,瀏覽器會自動在我們請求頭帶上一些標記。而上圖訪問網站的請求僅有請求地址。這時候聰明的讀者就要問了,那我們能不能也帶上瀏覽器的標識,從而讓京東網站以爲我們是通過瀏覽器訪問的,從而騙過它呢? 當然是可以的

我們先要了解瀏覽器是怎麼發送請求的:
在這裏插入圖片描述在這裏插入圖片描述

import requests

if __name__ == '__main__':
    url = 'https://search.jd.com/Search?keyword=aj1&enc=utf-8'  # 目標網站地址
    # 模擬瀏覽器訪問
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
        'accept-language': 'zh-CN,zh;q=0.9'
    }
    response = requests.get(url, headers=headers)  # 請求訪問網站
    html = response.text  # 獲取網頁源碼
    print(html)  # 將源碼打印到控制檯

在這裏插入圖片描述
對代碼稍作整理

import requests


def get_html(url):
    # 模擬瀏覽器訪問
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                      'AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/81.0.4044.138 Safari/537.36',
        'accept-language': 'zh-CN,zh;q=0.9'
    }
    print("--> 正在獲取網站信息")
    response = requests.get(url, headers=headers)  # 請求訪問網站
    if response.status_code == 200:
        html = response.text  # 獲取網頁源碼
        return html  # 返回網頁源碼
    else:
        print("獲取網站信息失敗!")
        

if __name__ == '__main__':
    # 搜索關鍵字
    keyword = 'aj1'
    # 搜索地址
    search_url = 'https://search.jd.com/Search?keyword=' + keyword + '&enc=utf-8'
    print(get_html(search_url))  # 將源碼打印到控制檯

2、篩選需要的信息

篩選信息就要用上文中提到的強大的第三方庫了 -> lxml,同時我們需要使用到bs4這個包。
但在這之前我們先要知道我們需要什麼信息。
在這裏插入圖片描述在這裏插入圖片描述

到這裏我們就已經知道商品的信息在哪裏了。所以我們可以排除其他干擾,<li>標籤下的就是我們要的。ok,開始擼代碼!
首先導入bs4包,然後就可以使用BeautifulSoup庫了,先上代碼

import requests
from bs4 import BeautifulSoup


def get_html(url):
    # 模擬瀏覽器訪問
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                      'AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/81.0.4044.138 Safari/537.36',
        'accept-language': 'zh-CN,zh;q=0.9'
    }
    print("--> 正在獲取網站信息")
    response = requests.get(url, headers=headers)  # 請求訪問網站
    if response.status_code == 200:
        html = response.text  # 獲取網頁源碼
        return html  # 返回網頁源碼
    else:
        print("獲取網站信息失敗!")


if __name__ == '__main__':
    # 搜索關鍵字
    keyword = 'aj1'
    # 搜索地址
    search_url = 'https://search.jd.com/Search?keyword=' + keyword + '&enc=utf-8'
    html = get_html(search_url)
    # 初始化BeautifulSoup庫,並設置解析器
    soup = BeautifulSoup(html, 'lxml')
    # 商品列表
    goods_list = soup.find_all('li', class_='gl-item')
    # 打印goods_list到控制檯
    print(goods_list)

soup = BeautifulSoup(html, ‘lxml’) 語句執行後,將解析的結果給soup,這時候我們可以使用BeautifulSoup提供的強大的解析方法了。首先我們來解釋一下爲什麼soup.find_all(‘li’, class_=‘gl-item’)可以獲取到商品列表,也就是前文提到的全部<li>標籤。
在這裏插入圖片描述在這裏插入圖片描述
我們執行代碼後,就可以獲取到所有的<li>標籤裏的內容了。然後可以把控制檯的輸出 -> 全選 -> 複製
-> 粘貼 到文本編輯器中,最好是支持html格式的,這樣可以格式化代碼,排版看起來舒服多了。這裏本人使用的是VS Code編輯器。這樣可以檢查一下爬取到是代碼是否正確。接下來我們要找到每個信息存在li裏的哪個標籤裏。大家可以在瀏覽器像剛剛找商品的li一樣,找到其他商品名、價格等信息的位置。下圖舉個栗子
在這裏插入圖片描述
剛剛已經使用過find_all()方法了,如果是找一個而不是全部,那就可以使用find()方法,獲取標籤內屬性的值:[屬性名’],獲取text:.get_text(),這兩種都是返回字符串類型str。
我們可以用for來遍歷goods_list,把值給li,這樣就可以每次單獨取一個li來操作了。
假如li是每個<li>標籤,那麼

  • 獲取商品編號就可以寫成:li[‘data-sku’]
  • 獲取圖片地址:li.find(class_=‘p-img’).find(‘img’)[‘src’]
  • 獲取價格:li.find(class_=‘p-price’).find(‘i’).get_text()
  • 獲取商品名稱:li.find(class_=‘p-name p-name-type-2’).find(‘em’).get_text()

琢磨一下,如果還是不清楚,可以搜索一下BeautifulSoup的用法。

import requests
from bs4 import BeautifulSoup


def get_html(url):
    # 模擬瀏覽器訪問
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                      'AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/81.0.4044.138 Safari/537.36',
        'accept-language': 'zh-CN,zh;q=0.9'
    }
    print("--> 正在獲取網站信息")
    response = requests.get(url, headers=headers)  # 請求訪問網站
    if response.status_code == 200:
        html = response.text  # 獲取網頁源碼
        return html  # 返回網頁源碼
    else:
        print("獲取網站信息失敗!")


if __name__ == '__main__':
    # 搜索關鍵字
    keyword = 'aj1'
    # 搜索地址
    search_url = 'https://search.jd.com/Search?keyword=' + keyword + '&enc=utf-8'
    html = get_html(search_url)
    # 初始化BeautifulSoup庫,並設置解析器
    soup = BeautifulSoup(html, 'lxml')
    # 商品列表
    goods_list = soup.find_all('li', class_='gl-item')
    # 打印goods_list到控制檯
    for li in goods_list:  # 遍歷父節點
        # 商品編號
        no = li['data-sku']
        # 商品名稱
        name = li.find(class_='p-name p-name-type-2').find('em').get_text()
        # 圖片路徑
        img_url = li.find(class_='p-img').find('img')['src']
        # 價格
        price = li.find(class_='p-price').find('i').get_text()
        # 商家
        shop = li.find(class_='p-shop').find('a').get_text()
        # 商品詳情地址
        detail_addr = li.find(class_='p-name p-name-type-2').find('a')['href']
        # 打印結果
        print("===================分割線=========================")
        print("商品編號 = " + no)
        print("商品名稱 = " + name)
        print("圖片路徑 = " + img_url)
        print("價格 = " + price)
        print("商家 = " + shop)
        print("商品詳情地址 = " + detail_addr)

如下圖,這樣就爬取到了我們需要的內容了
在這裏插入圖片描述

3、持久化數據

通過第二步,我們已經取到我們的數據了,但是我們是數據是存在內存中的,程序運行結束了,數據也就丟失了,雖然打印到控制檯了,但它並沒有寫到我們硬盤中,我關閉pycharm或者關閉電腦了也會丟失。所以要使我們爬取的數據持久化,我們就得把數據寫入到磁盤中。可以寫到數據庫,這樣方便對數據操作,也可以寫到txt文本。本例是把數據寫入到Excel文檔中。
使用xlwt庫,可以非常方便的把數據寫入到Excel中。
首先要先導入庫:import xlwt
創建Excle文件:xlwt.Workbook(encoding=‘ascii’)
添加一張單:write_work.add_sheet(“sheet1”)
我們新建Excel文檔,都會自己創建一張單,這裏的"sheet1",可以根據自己修改名字。
在這裏插入圖片描述
write_sheet = write_work.add_sheet(“sheet1”)。例如我們把新建的這個單返回後,賦值給write_sheet,那麼write_sheet.write([行],[列],label=[填充文本])
保存:write_work.save([保存地址])
具體代碼如下:


import requests
from bs4 import BeautifulSoup
import xlwt


def get_html(url):
    # 模擬瀏覽器訪問
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                      'AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/81.0.4044.138 Safari/537.36',
        'accept-language': 'zh-CN,zh;q=0.9'
    }
    print("--> 正在獲取網站信息")
    response = requests.get(url, headers=headers)  # 請求訪問網站
    if response.status_code == 200:
        html = response.text  # 獲取網頁源碼
        return html  # 返回網頁源碼
    else:
        print("獲取網站信息失敗!")


if __name__ == '__main__':
    # 創建workbook,就是創建一個Excel文檔
    write_work = xlwt.Workbook(encoding='ascii')
    # 添加一張單
    write_sheet = write_work.add_sheet("sheet1")
    # 創建表頭
    write_sheet.write(0, 0, label='商品編號')      # 第1行 第1列 寫入內容'商品編號'
    write_sheet.write(0, 1, label='商品名稱')      # 第1行 第2列 寫入內容'商品名稱'
    write_sheet.write(0, 2, label='圖片路徑')      # 第1行 第3列 寫入內容'圖片路徑'
    write_sheet.write(0, 3, label='價格')         # 第1行 第4列 寫入內容'價格'
    write_sheet.write(0, 4, label='商家')         # 第1行 第5列 寫入內容'商家'
    write_sheet.write(0, 5, label='商品詳情地址')   # 第1行 第6列 寫入內容'商品詳情地址'
    # 記錄當前行數
    _current_row = 0

    # 搜索關鍵字
    keyword = 'aj1'
    # 搜索地址
    search_url = 'https://search.jd.com/Search?keyword=' + keyword + '&enc=utf-8'
    html = get_html(search_url)
    # 初始化BeautifulSoup庫,並設置解析器
    soup = BeautifulSoup(html, 'lxml')
    # 商品列表
    goods_list = soup.find_all('li', class_='gl-item')
    # 打印goods_list到控制檯
    for li in goods_list:  # 遍歷父節點
        # 由於我們第一行已經寫入了表頭。所以這裏0+1,就是從第1行開始,後面每次循環+1
        _current_row += 1
        # 商品編號
        no = li['data-sku']
        # 商品名稱
        name = li.find(class_='p-name p-name-type-2').find('em').get_text()
        # 圖片路徑
        img_url = li.find(class_='p-img').find('img')['src']
        # 價格
        price = li.find(class_='p-price').find('i').get_text()
        # 商家
        shop = li.find(class_='p-shop').find('a').get_text()
        # 商品詳情地址
        detail_addr = li.find(class_='p-name p-name-type-2').find('a')['href']

        # 寫入Excel
        write_sheet.write(_current_row, 0, label=no)
        write_sheet.write(_current_row, 1, label=name)
        write_sheet.write(_current_row, 2, label=img_url)
        write_sheet.write(_current_row, 3, label=price)
        write_sheet.write(_current_row, 4, label=shop)
        write_sheet.write(_current_row, 5, label=detail_addr)

    # 保存文件,使用的是相對目錄(也可以使用絕對路徑),會保存在當前文件的同目錄下。文件名爲dj_data.xls,必須是.xls後綴
    write_work.save("./dj_data.xls")
    

執行代碼,然後在同級目錄下,就可以看到dj_data.xls文件,打開文件。可以看到已經爬取到了數據了。
在這裏插入圖片描述
整理一下代碼,把Excel操作部分提取到一個類中

#!/usr/bin/python

import requests
from bs4 import BeautifulSoup
import xlwt


class Excel:

    # 當前行數
    _current_row = 1

    # 初始化,創建文件及寫入title
    def __init__(self, sheet_name='sheet1'):
        # 表頭,放到數組中
        title_label = ['商品編號', '商品名稱', '圖片路徑', '價格', '商家', '商品詳情地址']
        self.write_work = xlwt.Workbook(encoding='ascii')
        self.write_sheet = self.write_work.add_sheet(sheet_name)
        for item in range(len(title_label)):
            self.write_sheet.write(0, item, label=title_label[item])

    # 寫入內容
    def write_content(self, content):
        for item in range(len(content)):
            self.write_sheet.write(self._current_row, item, label=content[item])
        # 插入完一條記錄後,換行
        self._current_row += 1

    # 保存文件(這裏的'./dj_data.xls'是默認路徑,如果調用此函數,沒有傳file_url參數,則使用'./dj_data.xls')
    def save_file(self, file_url='./dj_data.xls'):
        try:
            self.write_work.save(file_url)
            print("文件保存成功!文件路徑爲:" + file_url)
        except IOError:
            print("文件保存失敗!")


def get_html(url):
    # 模擬瀏覽器訪問
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
                      'AppleWebKit/537.36 (KHTML, like Gecko) '
                      'Chrome/81.0.4044.138 Safari/537.36',
        'accept-language': 'zh-CN,zh;q=0.9'
    }
    print("--> 正在獲取網站信息")
    response = requests.get(url, headers=headers)  # 請求訪問網站
    if response.status_code == 200:
        html = response.text  # 獲取網頁源碼
        return html  # 返回網頁源碼
    else:
        print("獲取網站信息失敗!")


if __name__ == '__main__':
    # 創建文件
    excel = Excel()
    # 搜索關鍵字
    keyword = 'aj1'
    # 搜索地址
    search_url = 'https://search.jd.com/Search?keyword=' + keyword + '&enc=utf-8'
    html = get_html(search_url)
    # 初始化BeautifulSoup庫,並設置解析器
    soup = BeautifulSoup(html, 'lxml')
    # 商品列表
    goods_list = soup.find_all('li', class_='gl-item')
    # 打印goods_list到控制檯
    for li in goods_list:  # 遍歷父節點
        # 商品編號
        no = li['data-sku']
        # 商品名稱
        name = li.find(class_='p-name p-name-type-2').find('em').get_text()
        # 圖片路徑
        img_url = li.find(class_='p-img').find('img')['src']
        # 價格
        price = li.find(class_='p-price').find('i').get_text()
        # 商家
        shop = li.find(class_='p-shop').find('a').get_text()
        # 商品詳情地址
        detail_addr = li.find(class_='p-name p-name-type-2').find('a')['href']
        # 將商品信息放入數組中,再傳到寫入文件函數
        goods = [no, name, img_url, price, shop, detail_addr]
        # 寫入文檔
        excel.write_content(goods)

    # 保存文件,使用的是相對目錄(也可以使用絕對路徑),會保存在當前文件的同目錄下。文件名爲dj_data.xls,必須是.xls後綴
    excel.write_work.save("./dj_data.xls")

4、擴展(分頁爬取)

通過前面的步驟,我們已經可以把數據爬取到並提取出來,再寫入文件了,但是聰明的讀者又要問了,在京東上,搜索AJ1,有100頁數據,每頁有幾十個商品,這爬蟲怎麼才爬了30+條。
di
在這裏插入圖片描述
這是因爲這些網站數據量太大,如果一次把所有的數據加載出來,可以我們打開一個頁面要等上幾分鐘,所以這些網站是有分頁的,也就是說你點第一頁的時候,它不會把2、3的內容傳輸過來,點第二頁的時候,才重新再發請求。那我們前面只發了一條請求,當然就只看到了第一頁的信息了。
在這裏插入圖片描述但是這裏會絕得很奇怪,爲什麼第二頁,但是page的參數是3而不是2呢,其實這個3對代碼來說,確實的第三頁,因爲京東第一頁翻到第二頁是用流加載的。也就是說,當你頁面滾到第第一頁末尾的時候,它會發一次請求第二頁,所以到你點第二頁的時候,已經是第三次請求了(第一次請求是剛進來頁面、第二次是滑倒底部流加載請求了一次,第三次是點第二頁的時候又請求了一次)。
分析到這裏那麼我們要請求更多的數據就改變page的值和s(當然s也可以不要)的值就可以啦。
關於分頁這部分代碼本文就不在做詳細解釋了。具有分頁功能的代碼會放到碼雲上。

4、代碼

碼雲地址:含分頁功能

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章