使用Scrapy Splash爬取京东手机信息

使用Scrapy Splash爬取京东手机信息

Splash是官推的js渲染引擎,和Scrapy结合比较好,使用的是webkit开发的轻量级无界面浏览器,
渲染之后结果和静态爬取一样可以直接用xpath处理。只是splash是在docker中运行。

scrapy-splash package网址:https://pypi.python.org/pypi/scrapy-splash

splash官网:http://splash.readthedocs.io/en/stable/scripting-ref.html
1 开发环境
windows 10
python3
vscode
docker
2 docker 安装
下载:https://store.docker.com/editions/community/docker-ce-desktop-windows
3 安装scrapy-splash
pip install scrapy-splash
运行splash
$ docker run -p 8050:8050 scrapinghub/splash
运行无异常之后,可以在浏览器中输入网址,看到运行效果,可以在右边自己写lua脚本测试是否达到效果,也自带了部分lua脚本可以查看

4 页面结构分析
demo是爬取京东图书关于python的图书,包含书名,价格,购买链接。京东页面在对商品的价格做了动态加载,页面切换也是用js去完成,所以在静态爬取无法实现。
先分析一下页面,用firefowx开发工具查看页面,京东在进入商品页面时只有30个item,
但是当把页面拉到底部时,会再次加载剩余部分30个item。我们在debug控制中输入js代码:
document.getElementById("J-global-toolbar").scrollIntoView()
实现自动设置可视到底部,达到页面自动加载全部item,这里用注意的是用 getElementsByClassName时没有scrollIntoView()方法。

在切换到下一页时,页面是调用的一个js方法 SEARCH.page(3, true),我们会调用此js进行自动换页,
当切换到到最后一页时,class=‘pn-next disabled’,这个作为我们判断是否已经爬取完所有页面。

综合上面分析,爬取过程是需先用lua脚本执行js加载完成整个页面,完成爬取之后判断是否已经是最后一页,再执行js跳转到下一页。
代码实现:
对setting.py进行配置

DOWNLOADER_MIDDLEWARES 中添加Splash middleware,未防止被发现发现是爬虫而被封,这里有添加User-Agent信息。
DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
    'jdscrapy.RandomUserAgent.RandomUserAgent':400
}

添加SPIDER_MIDDLEWARES
SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}

添加splash运行地址
SPLASH_URL = 'http://localhost:8050/'
添加DUPEFILTER_CLASS去重
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
主代码:
# -*- coding: utf-8 -*-
import re

import scrapy
from scrapy_splash import SplashRequest


def Getlua_next(pageNum):
    lua_next = """
    function main(splash)
        splash:go(splash.args.url)
        splash:wait(2)
        splash:runjs("SEARCH.page(%s, true)")
        splash:wait(2)
        return splash:url()
    end
    """ % (str(pageNum))
    return lua_next


class ExampleSpider(scrapy.Spider):
    name = 'jd'
    allowed_domains = ['jd.com']
    # start_urls = ['https://search.jd.com/Search?keyword=Python&enc=utf-8&wq=Python']
    def start_requests(self):
        scrapy = open("taobao.lua").read()
        url = "https://search.jd.com/Search?keyword=Python&enc=utf-8&wq=Python"
        yield SplashRequest(url=url,callback=self.parse,meta={"page":1},endpoint="execute",args={"lua_source":scrapy,"url":url})

    def parse_url2(self, response):
        scrapy = open("taobao.lua").read()
        url = response.body_as_unicode()
        # 加载剩余item
        yield SplashRequest(url, meta={'page': response.meta['page']}, endpoint='execute',args={'lua_source': scrapy})

    def parse(self, response):
        # with open("jj.html","a",encoding="utf-8") as f:
        #     f.write(response.text)
        pagenum = int(response.meta['page'])
        posts = response.css("li.gl-item")
        for post in posts:

            books = post.css("div.p-name > a > em").extract_first()

            bookname=re.compile(r'<.*?>').sub("",books)
            prices = post.css("div.p-price strong").extract_first()
            price = re.compile(r'<.*?>').sub("", prices)
            print(bookname)
            print(price)
            # 翻页 判断是否到最后一页

        if len(response.xpath('.//div[@class="pn-next disabled"]/em/b/text()').extract()) <= 0:
            yield SplashRequest(response.url,meta={'page':pagenum+1}, callback=self.parse_url2,endpoint='execute', args={"lua_source":Getlua_next(2*pagenum+1)}, dont_filter=True)

lua文件:lua文件一定要和你创建的项目同级
taobao.lua文件:
代码如下:
function main(splash)
        splash:set_user_agent("Mozilla/5.0  Chrome/69.0.3497.100 Safari/537.36")
        splash:go(splash.args.url)
        splash:wait(5)
        splash:runjs('document.getElementById("J-global-toolbar").scrollIntoView()')
        splash:wait(5)
        return {html=splash:html()}
end
扩展部分:京东的二段加载采用上面方法,如果不是二段加载则采用下面的lua方法。一直下拉加载就采用下面方法。
代码如下:
function main(splash, args)
                  splash:set_user_agent("Mozilla/5.0  Chrome/69.0.3497.100 Safari/537.36")
                  splash:go(args.url)
                  local scroll_to = splash:jsfunc("window.scrollTo")
                  scroll_to(0, 2800)
                  splash:set_viewport_full()
                  splash:wait(5)
                  return {html=splash:html()}
end
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值