Spider实战系列-一次真实接单经历让我抓取了某东的数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spider实战系列-一次真实接单经历让我抓取了某东的数据相关的知识,希望对你有一定的参考价值。

抓取JD商品

先说说起因吧,是因为有朋友找我一起合作抓取某东的商品数据,我做为一个刚入爬虫的新手,当然是不可能完整的拿下这个啦.这次爬虫要的是商品的详细数据,我的工作就是筛选所有的商品的url,解析成json文件,传给他,他在继续通过我传入的url进行商品的详细信息

需求

这次的需求是通过关键字,找出含有关键字信息的产品,并且按照高级筛选的条件,要前100条商品的数据,如下

Spider实战系列-一次真实接单经历让我抓取了某东的数据_json

还要根据销量,价格,评论数再来分别通过高级筛选来得到商品的url

Spider实战系列-一次真实接单经历让我抓取了某东的数据_json_02

这个就是我要完成的部分了

思路

  1. 在浏览器输入关键字某某某某,进入到页面

Spider实战系列-一次真实接单经历让我抓取了某东的数据_json_03

2. 分析页面源码,如何能抓取我们要的高级筛选的属性

Spider实战系列-一次真实接单经历让我抓取了某东的数据_json_04

3. 抓取筛选页的前100个商品url

代码实现+思路讲解

得到高级筛选的字段

Spider实战系列-一次真实接单经历让我抓取了某东的数据_json_05

在这里我们能看到,防水等级就是我们要的高级筛选的字段,但是其实还有一些问题吗,这里只给了我们防水等级并没有进入到具体的分类

Spider实战系列-一次真实接单经历让我抓取了某东的数据_爬虫_06

比如在防水等级里就有两个分类IPX7和不防水,我们就需要继续在页面内找,这两个字段在哪里,这时候就可以使用control+f来查找了

Spider实战系列-一次真实接单经历让我抓取了某东的数据_爬虫_07

"""

第一页
https://search.jd.com/search?keyword=%E6%99%BA%E8%83%BD%E9%99%AA%E4%BC%B4&ev=2342_80416%5E
https://search.jd.com/search?keyword=%E6%99%BA%E8%83%BD%E9%99%AA%E4%BC%B4&ev=2342_10097%5E

"""
import json

import re

import requests
from lxml import etree

"""
第二页
https://search.jd.com/search?keyword=%E6%99%BA%E8%83%BD%E9%99%AA%E4%BC%B4&&ev=2342_80416%5E&page=3&s=61&click=0

"""
headers=
cookie: jsavif=1; jsavif=1; __jda=122270672.1676954628911215392914.1676954629.1676954629.1676954629.1; __jdc=122270672; __jdv=122270672|direct|-|none|-|1676954628913; shshshfp=ed3eddd61f715d1c96c9f6c16fbe0b4d; shshshfpa=ad1721fc-fb58-e043-0884-f3e3ec7ecbfa-1676954631; shshshfpx=ad1721fc-fb58-e043-0884-f3e3ec7ecbfa-1676954631; rkv=1.0; shshshfpb=m7YIEJ4kE_I09iQUOqucbNw; __jdu=1676954628911215392914; avif=1; areaId=9; ipLoc-djd=9-687-0-0; wlfstk_smdl=yc99d5v35ijyw20zsopjutf8cepak91i; TrackID=1kdV6GF1RffnRbe0Qp0GpJB-SZpgdYbiwt7b0CEM2f-Qes4EHmzCguXvIxhLu0kyjLvRIBLlXSZowydOT8eGqpkOTUI-UdWXbh2BcVDzNdqI; pinId=BuFXDWEgSjOpfSLAe_c1dA; pin=jd_oLZlDnoADreu; unick=jd_oLZlDnoADreu; ceshi3.com=000; _tp=U7c%2B2nqfBmVC0%2FrGlXCSJw%3D%3D; _pst=jd_oLZlDnoADreu; qrsc=3; thor=2BFA8AF79CCDF02724AC400C4157CF8EBB31A9583271110F6E6D8E13410D78445553C630236F92E98969BCD22A8D8CB0C41302FC31CBE0A2317A9EC1ED0F91781CB9DF3D61A97C3F80AE2DE488F8C11C8A37877C14B238CC6C714C521F3D4B63F6D6E8CC26676776A9C222D368AB117C9DE11182B5067CA10404624893CF29452F53873DE232D1A749D694343D18A5C949A24608AB468A71576F0B45B2F1B5C6; __jdb=122270672.7.1676954628911215392914|1.1676954629; shshshsID=c9fb7fbdf834fc947f6247315a300911_5_1676955986077; 3AB9D23F7A4B3C9B=MH3KQE7TQIQI2EQYBOGYVWJVC4DHHDSOZY6GKNBSQ3Z3X5TGIDW7VHWUBMM3KQRB73QFJDNYEOKG6ZG7HSG4VXAKX4,
referer: https://www.jd.com/,
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.50

def select_url():
url=https://search.jd.com/search?keyword=%E6%99%BA%E8%83%BD%E9%99%AA%E4%BC%B4&psort=4&psort=4&pvid=945b3a4408f84c7ea93a498ea22afa8e&click=1
# 先抓取高级搜索的每个url
# 获取页面源码
response = requests.get(url, headers=headers)

tree = etree.HTML(response.content.decode(utf-8))

# 高级搜索中的每个url
# //ul[@class="menu"]/li[position()>1 and position()<5]
# 找到每一个ul下载li
li_list = tree.xpath(
//div[@class="sl-tab-cont"]/div[position()>0 and position()<10]/div[@class="sl-v-list"]/ul/li)
items=
item_list=[]
for li in li_list:
item=
broken_url = li.xpath(./a/@href)
broken_name = li.xpath(./a/@onclick)
ev = str.split(broken_url[0], &)[-1]
print(broken_name)
# 使用re来对
name = .join(re.findall("searchlog(.*?,(.*?))", .join(broken_name)))

item[ev]=ev
item[name]=name
item_list.append(item)
items[data] = item_list

with open(./高级筛选/综合-高级筛选.json,w,encoding=utf-8)as f:
f.write(json.dumps(items,ensure_ascii=False))


if __name__ == __main__:
select_url()
复制代码

这里需要注意一点,我们页面上显示的只有10个分类,所有div也只需要抓10就可以了,这时候div[position()>0 and position()<10]只需要这样写就可以了,跟切片的方法类似

li_list = tree.xpath(
//div[@class="
sl-tab-cont"]/div[position()>0 and position()<10]/div[@class="sl-v-list"]/ul/li)
复制代码

最后进行json文件的生成

结果

这里的url我没什么要用ev来截取出来,因为在后期的时候我们通过分析每一个详情页的时候,需要拼接url,这里我先跟大家说明一下,看到后面大家就理解了

Spider实战系列-一次真实接单经历让我抓取了某东的数据_数据_08

因为只需要三种类型综合,销量,评论数,后续的url会用到,所以我就手动的拼接进json的文件,为了后续的拼接整体的url

Spider实战系列-一次真实接单经历让我抓取了某东的数据_数据_09

综合Top100商品的url形成json文件

在这里我们就需要拼接url了

​search.jd.com/search?keyw…​

​search.jd.com/search?keyw…​

keyword就是我们输入的关键字

ev就是我们高级筛选出来的字段

pvid就是我们的根据销量筛选出来的

psort这个变量是根据销量和评论数得到的跟随变量

page这个是页面

s也是一个变量

import json
import os
import time
from selenium.webdriver.common.by import By
from selenium import webdriver

file_list = os.listdir(排名_json)

options = webdriver.ChromeOptions()
options.add_experimental_option(excludeSwitches, [enable-automation])
options.add_argument(--disable-blink-features=AutomationControlled)
# options.add_argument(--proxy-server=http://代理服务器:端口)
driver = webdriver.Chrome(options=options)
driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument,
"source":
Object.defineProperty(navigator,webdriver,
get:()=>undefined
)

)

headers =
cookie: jsavif=1; jsavif=1; __jda=122270672.1676954628911215392914.1676954629.1676954629.1676954629.1; __jdc=122270672; __jdv=122270672|direct|-|none|-|1676954628913; shshshfp=ed3eddd61f715d1c96c9f6c16fbe0b4d; shshshfpa=ad1721fc-fb58-e043-0884-f3e3ec7ecbfa-1676954631; shshshfpx=ad1721fc-fb58-e043-0884-f3e3ec7ecbfa-1676954631; rkv=1.0; shshshfpb=m7YIEJ4kE_I09iQUOqucbNw; __jdu=1676954628911215392914; avif=1; areaId=9; ipLoc-djd=9-687-0-0; wlfstk_smdl=yc99d5v35ijyw20zsopjutf8cepak91i; TrackID=1kdV6GF1RffnRbe0Qp0GpJB-SZpgdYbiwt7b0CEM2f-Qes4EHmzCguXvIxhLu0kyjLvRIBLlXSZowydOT8eGqpkOTUI-UdWXbh2BcVDzNdqI; pinId=BuFXDWEgSjOpfSLAe_c1dA; pin=jd_oLZlDnoADreu; unick=jd_oLZlDnoADreu; ceshi3.com=000; _tp=U7c%2B2nqfBmVC0%2FrGlXCSJw%3D%3D; _pst=jd_oLZlDnoADreu; qrsc=3; thor=2BFA8AF79CCDF02724AC400C4157CF8EBB31A9583271110F6E6D8E13410D78445553C630236F92E98969BCD22A8D8CB0C41302FC31CBE0A2317A9EC1ED0F91781CB9DF3D61A97C3F80AE2DE488F8C11C8A37877C14B238CC6C714C521F3D4B63F6D6E8CC26676776A9C222D368AB117C9DE11182B5067CA10404624893CF29452F53873DE232D1A749D694343D18A5C949A24608AB468A71576F0B45B2F1B5C6; __jdb=122270672.7.1676954628911215392914|1.1676954629; shshshsID=c9fb7fbdf834fc947f6247315a300911_5_1676955986077; 3AB9D23F7A4B3C9B=MH3KQE7TQIQI2EQYBOGYVWJVC4DHHDSOZY6GKNBSQ3Z3X5TGIDW7VHWUBMM3KQRB73QFJDNYEOKG6ZG7HSG4VXAKX4,
referer: https://www.jd.com/,
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.50




def get_good_url(url, ev_name, pvid_name, page):
file = fpvid_name_ev_name_page.json
if file in file_list:
return True
items =
item_list = []
count = 0 if page == 1 else 60
driver.get(url) # 遍历每个列表链接
time.sleep(1)
buffer() # 缓冲,使页面加载完整
number = int(driver.find_element(By.XPATH, //div[@id="J_topPage"]/span/i).text)
info = driver.find_elements(By.CLASS_NAME, gl-i-wrap) # 寻找商品链接的父阶
for data in info:
item =
# 获取商品列表页所有的商品链接
good_url = data.find_element(By.CLASS_NAME, p-img).find_element(By.TAG_NAME, a).get_attribute(
href)
good_price = data.find_element(By.CLASS_NAME, p-price).find_element(By.TAG_NAME,
strong).find_element(
By.TAG_NAME, i).text
good_name = data.find_element(By.CLASS_NAME, p-name).find_element(By.TAG_NAME,
a).find_element(
By.TAG_NAME, em).text

count += 1
print(正在爬取 + pvid_name + ev_name + + str(page - 1) + 页的数据)
item[good_url] = good_url
item[good_name] = good_name
item[good_price] = good_price
item[good_num] = count
item_list.append(item)
if count == 100:
break
items[goods_ingo] = item_list
with open(f排名_json/pvid_name_ev_name_page.json, w, encoding=utf-8)as f:
f.write(json.dumps(items, ensure_ascii=False))
time.sleep(2)
return True if number > 1 else False


def get_good_json():
"""
得到以综合排序的url
:return: 返回一个列表,列表里第一个集合是所有第一页的url,第二集合是第二页的url,最后相加
"""
keyword = %E6%99%BA%E8%83%BD%E9%99%AA%E4%BC%B4
# 综合高级筛选

with open(./高级筛选/综合-高级筛选.json, r, encoding=utf-8)as f:
content = f.read()
data = json.loads(content)
# print(type(data))
# print(data)
ev_name = data[data]
pvid = data[pvid]
# print(ev_name)
pages = [1, 3]
for item in ev_name:
ev = item[ev]
evName = item[name]
pvid_name = data[pvid_name]
# 所有高级筛选的
# 第一页数据
page1 = pages[0]
url1 = fhttps://search.jd.com/search?keyword=keyword&ev&page=page1&s=1&click=0&pvid=pvid
index = get_good_url(url1, evName, pvid_name, page1)
if index:
# 第二页数据
page2 = pages[1]
url2 = fhttps://search.jd.com/search?keyword=keyword&ev&page=page2&s=61&click=0&pvid=pvid
get_good_url(url2, evName, pvid_name, page2)


def buffer():
"""
定义函数缓慢拖拽页面,使其加载完成
:return:
"""
for i in range(25):
time.sleep(0.6)
driver.execute_script(window.scrollBy(0,500), )


if __name__ == __main__:
get_good_json()
复制代码

这里为什么定义了一个buffer函数,这个是因为当我们在滑动网页的时候只显示前30条商品的数据,只有在滑动条到达某一个临界值的时候,才会加载后面的数据,这个叫做懒加载机制,这样网站是为了节省流量,所以我采用的是selenium进行一个dom操作进行网页的下滑,这里还需要注意的一点就是我们需要进行一个睡眠操作,不然就会因为滑动过快导致页面资源加载不出来,就会报错.

def buffer():
"""

定义函数缓慢拖拽页面,使其加载完成
:return:
"""
for i in range(25):
time.sleep(0.6)
driver.execute_script(window.scrollBy(0,500), )
复制代码

这里我们我进行了一个骚操作,因为客户要的只是前两页100条的数据,所以有些就固定写死就可以了,后期我们还要分页第一页第二页,这个数据也是要作为函数的变量传进去,后续会体现到这个参数的作用

with open(./高级筛选/综合-高级筛选.json, r, encoding=utf-8)as f:
content = f.read()
data = json.loads(content)
# print(type(data))
# print(data)
ev_name = data[data]
pvid = data[pvid]
# print(ev_name)
pages = [1, 3]
for item in ev_name:
ev = item[ev]
evName = item[name]
pvid_name = data[pvid_name]
# 所有高级筛选的
# 第一页数据
page1 = pages[0]
url1 = fhttps://search.jd.com/search?keyword=keyword&ev&page=page1&s=1&click=0&pvid=pvid
index = get_good_url(url1, evName, pvid_name, page1)
if index:
# 第二页数据
page2 = pages[1]
url2 = fhttps://search.jd.com/search?keyword=keyword&ev&page=page2&s=61&click=0&pvid=pvid
get_good_url(url2, evName, pvid_name, page2)
复制代码
进行每一页商品的查询

这里的逻辑是这样的,如果有第二页就说明能继续爬第二页的数据,并且定义一个计数器,这个计数器的作用是记录第一页的60条数据,并且把这个数据作为第二页的起始数据,查到第100条就结束,如果没有第二页的数据,就正常的查,并且录入

def get_good_url(url, ev_name, pvid_name, page):
file = fpvid_name_ev_name_page.json
if file in file_list:
return True
items =
item_list = []
count = 0 if page == 1 else 60
driver.get(url) # 遍历每个列表链接
time.sleep(1)
buffer() # 缓冲,使页面加载完整
number = int(driver.find_element(By.XPATH, //div[@id="J_topPage"]/span/i).text)
info = driver.find_elements(By.CLASS_NAME, gl-i-wrap) # 寻找商品链接的父阶
for data in info:
item =
# 获取商品列表页所有的商品链接
good_url = data.find_element(By.CLASS_NAME, p-img).find_element(By.TAG_NAME, a).get_attribute(
href)
good_price = data.find_element(By.CLASS_NAME, p-price).find_element(By.TAG_NAME,
strong).find_element(
By.TAG_NAME, i).text
good_name = data.find_element(By.CLASS_NAME, p-name).find_element(By.TAG_NAME,
a).find_element(
By.TAG_NAME, em).text

count += 1
print(正在爬取 + pvid_name + ev_name + + str(page - 1) + 页的数据)
item[good_url] = good_url
item[good_name] = good_name
item[good_price] = good_price
item[good_num] = count
item_list.append(item)
if count == 100:
break
items[goods_ingo] = item_list
with open(f排名_json/pvid_name_ev_name_page.json, w, encoding=utf-8)as f:
f.write(json.dumps(items, ensure_ascii=False))
time.sleep(2)
return True if number > 1 else False
复制代码

Spider实战系列-一次真实接单经历让我抓取了某东的数据_爬虫_10

Spider实战系列-一次真实接单经历让我抓取了某东的数据_数据_11

总结

我们在使用selenium进行元素定位的时候,比如

info = driver.find_elements(By.CLASS_NAME, gl-i-wrap) # 寻找商品链接的父阶

这里我们使用的并不是By.XPATH,如果是在这个节点之下使用的By.XPATH,这是会报错,说他的类型不匹配.我们就还是需要使用find_element(By.CLASS_NAME,来清洗数据

还有一点,就是如果说我们在把数据保存在本地的时候,如果说有一处报错,那么这出报错我们也不知道在哪里,也不知道这个数据有没有抓取成功

def get_good_url(url, ev_name, pvid_name, page): 

file = fpvid_name_ev_name_page.json
if file in file_list:
return True
复制代码

这个我们就是读取的文件名,如果这个文件名存在就说明我们能爬的到这个一个类型的json文件,就直接返回true,因为这个函数在另一个函数的for循环内,就说明跳出了这个循环,虽然这个方法也是有点慢,需要一个个检索文件名,但是好处就是我们不会重复的读取网页中每一个内容,在一定程度上,我们把代码的运行速度变快了.

以上是关于Spider实战系列-一次真实接单经历让我抓取了某东的数据的主要内容,如果未能解决你的问题,请参考以下文章

Spider理论系列-bs4

Spider实战系列-爬取鬼吹灯小说

记录一次真实的接单记录:猫眼电影数据可视化,三个小时完成收入1000

OKHttp实战篇(内部附赠真实案例+源码大公开)

Python爬虫之Scrapy框架系列——项目实战某瓣Top250电影所有信息的txt文本存储

Web Spider实战1——简单的爬虫实战(爬取"豆瓣读书评分9分以上榜单")