首页 > 其他分享 >Spider实战系列-一次真实接单经历让我抓取了某东的数据

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

时间:2023-03-02 16:05:55浏览次数:62  
标签:good name item url Spider 某东 pvid 接单 ev

抓取JD商品

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

需求

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

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

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

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

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

思路

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

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

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

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

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

代码实现+思路讲解

得到高级筛选的字段

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

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

Spider实战系列-一次真实接单经历让我抓取了某东的数据_json_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实战系列-一次真实接单经历让我抓取了某东的数据_json_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 = f'{pvid_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 = f'https://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 = f'https://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 = f'https://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 = f'https://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 = f'{pvid_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实战系列-一次真实接单经历让我抓取了某东的数据_json_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 = f'{pvid_name}_{ev_name}_{page}.json'
if file in file_list:
return True
复制代码

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

标签:good,name,item,url,Spider,某东,pvid,接单,ev
From: https://blog.51cto.com/u_15915681/6093637

相关文章

  • spider_ip代理 - 验证
    title:spider_ip代理-验证author:杨晓东&敖昀阳permalink:spider_ip代理-验证date:2021-10-0211:27:04categories:-投篮tags:-demospider_ip代理-验......
  • Spider理论系列-urllib
    tnnd,u1s1,爬取jd是真的der,尤其是要根据高级筛选查goods的url,这叫一个麻烦,博主目前正在小小的爬一些数据,等后整理出来jd的会发一篇实战的文章前情摘要一、web请求全过程......
  • Day21 21.2:CrawlSpider-redis分布式爬虫
    CrawlSpider-redis分布式分布式在日常开发中并不常用,只是一个噱头!概念:可以使用多台电脑搭建一个分布式机群,使得多台对电脑可以对同一个网站的数据进行联合且分布的......
  • CrawlSpider(全站数据爬取)
    CrawlSpider(全站数据爬取)实现网站的全站数据爬取就是将网站中所有页码对应的页面数据进行爬取。crawlspider其实就是scrapy封装好的一个爬虫类,通过该类提供的相......
  • Spider理论系列-bs4
    终于到了bs4了,有一说一,用了这么久的筛选数据的方法,用的最多的还是xpath,xpath无论是初学者理解还是使用都很方便,可以在我的实战文章里看到xpath的使用,xpath1、xpath安......
  • pgspider v0.20 之后的一些变动
    很久没太关注pgspider,发现v0.20之后不像以前版本那样了(patch模式),v0.20之后包含了自己的一个pg分支,同时端口进行了一些调整(pgspider自己的进程名称以及端口)支持的特......
  • pgspider 发布v0.3.0 了
    很久没太关注pgspid了,就在最近发布了v0.3.0不少bugfix新特性支持pg15.0支持多租户表的修改支持multitenant命令添加性能评估函数支持joinwhere美剧和以及ord......
  • Spider理论系列-bs4
    写在前面bs4最直接的应用就是我在爬取​​Spider实战系列-爬取鬼吹灯小说_浅辄的技术博客_51CTO博客​​这一篇里,我同时使用了bs4和xpath,相对于特定的情况,速度也会有所......
  • 推荐一个程序员接单平台,认证就白嫖50块,写个功能就能技术入股
    一直以为自己出身寒门呀,原来寒门是指势力较低的世家。我不是寒门,再怎么也得是个庶民吧!鬼知道这个庶民是指有房有钱的人。古代没有房叫做氓,没有钱叫做流,简称就是流氓。不服......
  • 推荐一个程序员接单平台,认证就白嫖50块,写个功能就能技术入股
    一直以为自己出身寒门呀,原来寒门是指势力较低的世家。我不是寒门,再怎么也得是个庶民吧!鬼知道这个庶民是指有房有钱的人。古代没有房叫做氓,没有钱叫做流,简称就是流氓。不......