python scrapy结合selenium爬取JD数据

python scrapy结合selenium爬取JD数据

JD的数据是js动态加载的需要selenium模拟鼠标动作向后滑动才加载完成,但是单纯的用selenium又很慢,所以用selenium和scrapy框架结合一下,会快一些。

第一步:创建scrapy文件

scrapy startproject JDpa
cd JDpa
scrapy genspider JD

打开 JD.py
分析jd页面数据
这里我查找的是jd关于python爬虫的相关信息
在这里插入图片描述
可以看到所有的信息都在ul标签下的li标签列表里面所以
li_list = response.xpath('//*[@id="J_goodsList"]/ul/li') 就可以拿到所有的li标签
遍历li_list拿到所有我要的内容
价格:在li标签下的div[@class="p-price"]下的strong标签下的i标签里面以文本形式储存所以

# 因为div[@class="p-price"]不是直属li标签,中间隔着一个div标签所以是 './/',如果直属的话就是'./'
price = li.xpath('.//div[@class="p-price"]/strong/i/text()')[0]

在这里插入图片描述
出版方:在li标签下的div[@class=“p-shopnum”]下的a标签的title属性值所以

shop = li.xpath('.//div[@class="p-shopnum"]/a/@title')[0]

在这里插入图片描述
标题,评价都是和前面一样就不多做赘述。

# 标题在em标签中但是又被分割成了几个font标签所以要用'//text()'才能拿到完整的文本信息
# ''.join()方法把name转换成字符串形式 
# '//text()'拿到的文本信息会有多余的空格和和换行符 用'.strip()'方法去掉两侧多余的空格和和换行符
name = li.xpath('.//div[@class="p-name"]/a/em//text()')
name = ''.join(name).strip() 
commit = li.xpath('.//div[@class="p-commit"]/strong/a/text()')[0]

在这里插入图片描述

在这里插入图片描述
这样一页数据就都获取了,接下来分析,页面直接URL的规律。

前面“https://search.jd.com/Search?keyword=python%E7%88%AC%E8%99%AB&suggest=1.his.0.0
&wq=python%E7%88%AC%E8%99%AB” 这一段都是一样的
&page=1&s=1&click=0
&page=3&s=58&click=0
&page=5&s=121&click=0
&page=7&s=176&click=0
可以看出page=后面是按照n从o开始,2n+1的方式排列的,而s=后面的数字没什么规律,后来我把&s=1&click=0这一段删除后,依然可以正常请求到页面信息,到这里页面URL的规律就找出来了。
在这里插入图片描述
一共有100页,所有的url可以表达为:

for i in range(100):
    url = 'https://search.jd.com/Search?keyword=python%E7%88%AC%E8%99%AB&suggest=1.his.0.0
&wq=python%E7%88%AC%E8%99%AB&page='+str(i*2+1)
    

第二步:

  1. 在爬虫文件中实例化浏览器对象
 def __init__(self):
        option = ChromeOptions()
        option.add_experimental_option('excludeSwitches', ['enable-automation'])
        self.bro = webdriver.Chrome(options=option)
  1. 下载中间键拦截所有的url请求,调用selenium请求,然后返回用selenium请求返回的响应对象。
    点开middlewares.py
    可以把不用的都删掉,只用
    def process_response(self, request, response, spider):
        # 创建浏览器实例化对象在爬虫文件中,用spider.bro调用
        bro = spider.bro 
        # requst.url 就是拦截到的爬虫文件发起的url
        bro.get(request.url)
        # selenium模拟鼠标下拉
        for i in range(25):
            time.sleep(0.3)
            bro.execute_script('window.scrollBy(0,300)', '')
        time.sleep(3)
        page = bro.page_source
        # 利用HtmlResponse()实例化一个新的响应对象
        n_response = HtmlResponse(url=request.url, body=page, encoding='utf-8', request=request)
        # 返回新的响应对象
        return n_response

第三步:

  1. 打开items.py文件,将解析到的数据定义为item类型对象的属性
class JdpaItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()
    price = scrapy.Field()
    commit = scrapy.Field()
    shop = scrapy.Field()

  1. 打开pipelines.py文件,接收item封装的数据并做持久化存储(写入本地xls表格)
from openpyxl import Workbook

class JdpaPipeline:
    def __init__(self):
        self.wb = Workbook()
        self.ws = self.wb.active
        self.ws.append(['书名', '价格', '评价', '出版方'])
    def process_item(self, item, spider):
        line = [item['name'], item['price'], item['commit'], item['shop']]
        self.ws.append(line)
        self.wb.save('./JD python爬虫相关书籍.xls')
        return item

3.打开setting.py文件

# 关闭robots协议
ROBOTSTXT_OBEY = False
# 输出日志设为之输出发生错误的日志信息
LOG_LEVEL = 'ERROR'
# 开启下载中键件
DOWNLOADER_MIDDLEWARES = {
   'JDpa.middlewares.JdpaDownloaderMiddleware': 543,
}
# 开启管道
ITEM_PIPELINES = {
   'JDpa.pipelines.JdpaPipeline': 300,
}

爬虫文件(JD.py)的完整代码:
这里解析shop的数据按照我之前第一步分析的那样写是有错误的,这个我写完运行之后就出门了,等我回来发现,每页60条数据,一共1000页,我这里只拿到了5800多条数据,而且输出日志有报错list index out of range,指出是shop = li.xpath('.//div[@class="p-shopnum"]/a/@title')[0]这一行,后来找了好久才发现有的是京东自营的,页面shop这一数据的位置就不对了,就会出现定位不到的情况。我这里改正了用try...except 做异常处理,把定位不到的shop 就直接等于’京东自营‘,后又测试了十几页,是正常的了。
附上京东自营的截图,可以看到根本就没有a标签,所以定位不到在这里插入图片描述

import scrapy
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from JDpa.items import JdpaItem

class JdSpider(scrapy.Spider):
    name = 'JD'
    #allowed_domains = ['www.xxx.com']
    start_urls = ['https://search.jd.com/Search?keyword=python%E7%88%AC%E8%99%AB&suggest=1.his.0.0&wq=python%E7%88%AC%E8%99%AB&page='+str(i*2+1) for i in range(100)]

    def __init__(self):
        # 实例化浏览器对象
        option = ChromeOptions()
        option.add_experimental_option('excludeSwitches', ['enable-automation'])
        self.bro = webdriver.Chrome(options=option)
    def parse(self, response):
        item = JdpaItem()
        li_list = response.xpath('//*[@id="J_goodsList"]/ul/li')
        for li in li_list:
            name = li.xpath('.//div[@class="p-name"]/a/em//text()').extract()
            name = ''.join(name).strip()
            price = li.xpath('.//div[@class="p-price"]/strong/i/text()')[0].extract()
            commit = li.xpath('.//div[@class="p-commit"]/strong/a/text()')[0].extract()
            try:
                shop = li.xpath('.//div[@class="p-shopnum"]/a[1]/@title')[0].extract()
            except:
                shop = '京东自营'
            item['name'] = name
            item['price'] = price
            item['commit'] = commit
            item['shop'] = shop
            yield item
    # 关闭浏览器
    def closed(self, spider):
        self.bro.close()

items.py完整代码:

import scrapy


class JdpaItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()
    price = scrapy.Field()
    commit = scrapy.Field()
    shop = scrapy.Field()

middlewares.py 完整代码:

from scrapy.http import HtmlResponse
from time import sleep

class JdpaDownloaderMiddleware:

    def process_response(self, request, response, spider):
        bro = spider.bro
        bro.get(request.url)
        for i in range(25):
            sleep(0.3)
            bro.execute_script('window.scrollBy(0,300)', '')
        sleep(3)
        page = bro.page_source
        n_response = HtmlResponse(url=request.url, body=page, encoding='utf-8', request=request)
        return n_response

pipelines.py 完整代码:

from openpyxl import Workbook

class JdpaPipeline:
    def __init__(self):
        self.wb = Workbook()
        self.ws = self.wb.active
        self.ws.append(['书名', '价格', '评价', '出版方'])
    def process_item(self, item, spider):
        line = [item['name'], item['price'], item['commit'], item['shop']]
        self.ws.append(line)
        self.wb.save('./JD2 python爬虫相关书籍资料.xls')
        return item


到这里就结束了!!!
在这里插入图片描述

在这里插入图片描述
就前面几十的评论多一些,后面的都没什么评论。
看来正在热门的也就几十本书。

### 编写Python网络爬虫程序以爬取京东数据 #### 开发工具的选择 对于编写能够从京东网站抓取数据Python网络爬虫,选择合适的开发工具有助于提高效率。Python本身是一个非常灵活的语言,在处理这类任务时表现尤为出色。为了更好地完成这项工作,可以利用几个重要的库: - **Requests**: 这个库允许开发者向目标服务器发送HTTP请求从而获取页面的内容[^2]。 - **BeautifulSoup 或 lxml**: 它们擅长解析HTML和XML文档,使得从中抽取特定的信息变得简单快捷。 - **Scrapy**: 当面对更复杂的项目需求时,这个框架提供了一套全面的功能集合,涵盖了从发起请求到最后保存所获数据的所有环节。 另外,如果遇到动态加载内容的情况,则可能需要用到Selenium配合WebDriver来进行自动化操作,比如模拟真实用户的浏览行为来绕过某些反爬机制[^4]。 #### 实现过程概览 下面给出一段简单的代码片段展示如何通过`requests`和`beautifulsoup4`这两个库去访问指定的商品详情页并提取其中的部分信息(注意实际应用中还需要考虑更多细节如异常处理等): ```python import requests from bs4 import BeautifulSoup def fetch_jd_product_info(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', } response = requests.get(url, headers=headers) soup = BeautifulSoup(response.text, 'html.parser') title_tag = soup.find('div', attrs={'class': 'sku-name'}) price_tag = soup.find('span', attrs={'class': 'price J-p-'}) product_title = title_tag.string.strip() if title_tag else None product_price = float(price_tag['data-price']) if price_tag and 'data-price' in price_tag.attrs else None return {'title': product_title, 'price': product_price} url_example = "https://item.jd.com/12345.html" product_data = fetch_jd_product_info(url_example) print(f"Product Title: {product_data['title']}") if product_data['price']: print(f"Price: ¥{product_data['price']:.2f}") else: print("Price not found.") ``` 这段脚本定义了一个函数`fetch_jd_product_info()`接收商品链接作为参数,并尝试读取出该产品的名称以及价格字段。需要注意的是这里仅作为一个基本示例,真实的环境中应当更加严谨地对待每一个步骤,包括但不限于设置合理的等待时间间隔、妥善管理会话状态等等。 #### 数据合法性与道德考量 值得注意的一点是在进行任何形式的数据收集活动之前都应该仔细阅读目标站点的服务条款,确保自己的做法既合法又符合伦理标准。此外,频繁的大规模请求可能会给对方服务器带来负担甚至违反服务协议,因此建议始终遵循robots.txt文件指示并且控制好频率。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无恶不作杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值