python 爬虫抓取某电商页面的商品价格

python 爬虫抓取某电商页面的商品价格

1. 业务需求

最近想通过爬虫抓取某电商商品页的商品详情, 浏览器页面打开如下: 本来以为是一个很简单的爬虫,却没想到一波三折,并没有那么简单。

2. 付诸实践

接到任务后,就兴冲冲的写了段代码来爬取网页数据。

# 厨房卫浴

href = 'http://search.gome.com.cn/search?question=%E5%8E%A8%E6%88%BF%E5%8D%AB%E6%B5%B4'

res = requests.get(href)

# print(res.text)

soup = BeautifulSoup(res.text, 'html.parser')

# product_list = soup.find('li', class_='product-item hideSmallBox')

# print(product_list)

product_list = soup.find_all('li', attrs={'class': 'product-item hideSmallBox'})

for item in product_list:

if type(item) is bs4.element.Tag:

print(item)

sku_id = item.get('skuid')

"""

title="宜来卫浴厨房龙头E-49018镀铬"

track="产品列表图片">宜来卫浴厨房龙头E-49018镀铬

src="//app.gomein.net.cn/images/grey.gif"/>

"""

emcode_item = item.find('a', class_='emcodeItem item-link')

item_title = emcode_item.attrs['title']

item_url = emcode_item.attrs['href']

"""

宜来卫浴厨房龙头E-49018镀铬

src="//app.gomein.net.cn/images/grey.gif"/>

"""

item_image_tag = emcode_item.find('img')

item_image_url = item_image_tag.attrs['gome-src']

执行任务后,好像哪里不对,遇到了意想不到的问题。

3. 出现问题

问题来了,查看网页源代码是能看到价格的,如下: 但是我通过BeautifulSoup解析后却死活找不到价格在那里。如下图,本应出现在price的标签中的价格呢? 后来检查了一通,才知道该电商页面的价格是通过js加载的,这也是一般电商行业防爬虫的手段之一,也就是说直接获取html的是不能的。

4. 找出问题

F12 打开这个页面,按住Ctrl + F 调出左侧搜索框,搜索价格: 经过一通排查,终于发现了猫腻,原来价格获取藏在这里,接下来又是一顿操作终于找到藏在深处的获取价格的url,如下图:

把这个链接拿出来: http://ss.gome.com.cn/search/v1/price/single/1001/G001/9140257462/1130961371/11010000/flag/item/fn1616072940509?callback=fn1616072940509&_=1616072940509

这个就是该电商商品页的价格获取链接,然后再来看看响应吧:

fn1616072940509({

"success": true,

"result": {

"price": "299.0",

"priceType": "RUSHBUYPRICE",

"productId": "9140257462",

"skuId": "1130961371"

}

})

我们解析一下上面的url,9140257462是productId,1130961371是skuId,这两个值都可以从HTML中获取到,然后再研究一下这个链接,发现还有三个参数未知: 经过N次的摸索测试,发现这三个参数如果不知道就都写成null就好了,这应该是该电商的一个漏洞吧,而且按照下面的连接请求,也能获取到价格:

http://ss.gome.com.cn/search/v1/price/single/null/null/9140257462/1130961371/null/flag/item

截止到此,已经探索出来商品的价格获取链接了,然后又赶紧改进代码,增加一个获取价格的方法:

def get_item_price(product_id, skuid):

"""

:param product_id: 商品id

:param skuid: skuId

:return: 返回价格

"""

price_url = 'http://ss.gome.com.cn/search/v1/price/single/null/null/' + product_id + '/' + skuid + '/null/flag/item'

headers = {

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '

'(KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'

}

response = requests.get(price_url, headers=headers, timeout=30)

if response.status_code == 200:

return response.json()['result']['price']

else:

return "价格未知"

5. 最终代码

找到问题所在之后,确定最终代码:

# encoding: utf-8

import bs4

import requests

from bs4 import BeautifulSoup

import csv

import os

import platform

# 全局变量 用来计算一共爬虫爬了多少条数据

counter = 0

file = ''

project = ''

def write_fo_file(file_path, rows_data, *is_touch_file):

"""

:param file_path:

:param rows:

:param is_touch_file:

:return:

"""

if is_touch_file and is_touch_file[0] == 1:

# sys_str = platform.system()

# if sys_str == "Windows":

# if not os.path.exists(file_path):

# os.system(r"type nul > {}".format(file_path))

# else:

# print(file_path, '文件已存在')

# elif sys_str == "Linux":

# if not os.path.exists(file_path):

# os.system(r"touch {}".format(file_path))

# else:

# print(file_path, '文件已存在')

# else:

# print("Other System tasks: %s" % sys_str)

global file

file = file_path

with open(file_path, "a", newline="", encoding='utf-8-sig') as csvfile:

rows = ("商品名称", "商品productID", "商品sku_id", '商品链接', '商品图片', '商品价格')

writer = csv.writer(csvfile)

writer.writerow(rows)

csvfile.flush()

csvfile.close()

else:

with open(file_path, "a", newline="", encoding='utf-8-sig') as csvfile:

writer = csv.writer(csvfile)

# 批量写入文件

for row_data in rows_data:

writer.writerow(row_data)

csvfile.flush()

csvfile.close()

def get_product_lists(product_lists):

item_lists = []

for item in product_lists:

if type(item) is bs4.element.Tag:

# print(item)

sku_id = item.get('skuid')

pid = item.get('pid')

"""

样例数据:

title="宜来卫浴厨房龙头E-49018镀铬"

track="产品列表图片">宜来卫浴厨房龙头E-49018镀铬

src="//app.gomein.net.cn/images/grey.gif"/>

"""

emcode_item = item.find('a', class_='emcodeItem item-link')

item_title = emcode_item.attrs['title']

item_url = emcode_item.attrs['href']

"""

样例数据:

宜来卫浴厨房龙头E-49018镀铬

src="//app.gomein.net.cn/images/grey.gif"/>

"""

item_image_tag = emcode_item.find('img')

item_image_url = item_image_tag.attrs['gome-src']

item_price = get_item_price(product_id=pid, skuid=sku_id)

info = {'name': item_title, 'pid': pid, 'sku_id': sku_id, "href": item_url,

'image': item_image_url, 'price': item_price}

item_info = (item_title, pid, sku_id, 'http:' + item_url, 'http:' + item_image_url, item_price)

item_lists.append(item_info)

return item_lists

def get_page(url, page_num):

"""

:param url: 要爬取页面的url

:param page_num: 要爬取的页数

:return:

"""

headers = {

"Accept": "application/json, text/javascript, */*; q=0.01",

"Host": "search.gome.com.cn",

"Referer": "http://search.gome.com.cn/search?question=%E5%8E%A8%E6%88%BF%E5%8D%AB%E6%B5%B4",

"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36",

'X-Requested-With': 'XMLHttpRequest'

}

"""

Chengyanan 注:

如果为了更好的展示数据效果,可将下列type 改为json即可

我这里是为了更好的使用BeautifulSoup解析,所以用了默认的HTML类型

"""

for i in range(1, page_num + 1):

formdata = {

"facets": '',

"page": i,

# "type": "json",

"aCnt": 0

}

# print([url, formdata])

try:

r = requests.post(url, data=formdata, headers=headers)

soup = BeautifulSoup(r.text, 'html.parser')

product_list = soup.find('ul', class_='product-lists clearfix')

items = get_product_lists(product_list)

global counter

counter += items.__len__()

print(r"当前正在爬取的项目是{},一共需要爬取{}页,正在爬取第{}页,本页爬取数据{}条,累计爬取{}条..."

.format(project, page_num, i, items.__len__(), counter))

write_fo_file(file, items)

except Exception as e:

print(e)

print('链接失败')

def get_item_price(product_id, skuid):

"""

:desc 根据输入的产品id 和 skuid 获取商品的价格

:param product_id: 商品id

:param skuid: skuId

:return: 返回价格

"""

price_url = 'http://ss.gome.com.cn/search/v1/price/single/null/null/' + product_id + '/' + skuid + '/null/flag/item'

headers = {

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '

'(KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'

}

response = requests.get(price_url, headers=headers, timeout=30)

if response.status_code == 200:

return response.json()['result']['price']

else:

return "价格未知"

if __name__ == '__main__':

# 家居家装下分类品牌

dicts = {

"厨房卫浴": 'chu_fang',

"灯饰照明": 'deng_shi',

# "五金电料": 'wujin',

# "装修材料": 'zhuangxiu',

"客厅家具": 'keting',

"卧室家具": 'woshi',

"储物家具": 'chuwu',

"办公家具": 'bangong'

}

for i in dicts.items():

project = i[0]

write_fo_file(r'gm_spider_{}.csv'.format(i[1]), '', 1)

get_page(r'http://search.gome.com.cn/search?question={}'.format(i[0]), 4)

爬取结果

关注一下:

相关推荐

为什么会有“讨好型人格”,这群人到底怎么想的
彩票365官网下载安装

为什么会有“讨好型人格”,这群人到底怎么想的

📅 08-21 👁️ 9052
劳斯莱斯星空顶是哪款
365网站取款不给怎么办

劳斯莱斯星空顶是哪款

📅 07-21 👁️ 4637
电脑主板更换教程(逐步教你如何更换电脑主板,轻松提升电脑性能)