从零开始学爬虫(三)

345 阅读3分钟

在上一篇文章中,我们简单学习了如何用scrapy框架对豆瓣top250电影进行简单的爬虫。

但上一篇文章中还只是进行了最基本的数据爬取,本篇文章会针对以下两种情况,介绍常用的解决方法

  • 需要登陆鉴权
  • 爬取的内容是通过js动态渲染的

js动态渲染

首先还是和上一篇文章一样,搭一个初始的scrapy框架

scrapy startproject spider_test

创建一个login item

scrapy genspider LoginItem "https://bbs.gter.net/thread-XXXXX.html"

这次我们来尝试一下爬取寄托天下论坛的一篇帖子(仅做学习使用,不要用于其他用途),上面的url换成你想爬的网站。

image.png 比如我们要爬取这个通知时间,可是需要登陆后才能查看

image.png 登陆鉴权我们下一节再介绍,如果我们用postman去post这个url

image.png 可以看到实际上它的内容和F12看到的是不一样的

我们先尝试一下根据xpath强行爬取一下是什么结果

image.png 修改LoginItem.py 如下(记得修改url)

class LoginItemSpider(scrapy.Spider):
    name = 'login'
    allowed_domains = [' ']
    start_urls = ['https://bbs.gter.net/thread-XXXXX.html']
    spider_url = []

    def start_requests(self):

        yield scrapy.Request(url=self.start_urls[0], callback=self.parse)

    def parse(self, response):
        time = response.xpath(
            '//html/body/div[7]/div[5]/div[2]/div[1]/div/div/table/tbody/tr[1]/td[2]/div[2]/div/div[1]/div/table[1]/tbody/tr[8]/td/a/text()').extract_first()
        print("res:", time)

image.png

爬出来的结果是None,原因是这部分内容是通过js异步渲染的,我们拿到的html是没有这个内容的

image.png

要解决这个问题,需要用scrapy-splash这个框架来先进行渲染,然后再爬取.

splash是一个JavaScript渲染服务。它是一个实现了HTTP API的轻量级浏览器,splash使用python实现的,同时使用Twisted和QT.

docker安装和部署

docker run -p 8050:8050 scrapinghub/splash

浏览器输入http://localhost:8050/ 如果界面如下则启动成功

image.png

在setting.py中添加如下配置

ROBOTSTXT_OBEY = False

USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'
SPLASH_URL = 'http://localhost:8050'

DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}

# 去重过滤器
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
# 使用Splash的Http缓存
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

useragent是用于反爬虫的,DOWNLOADER_MIDDLEWARES设置了不同中间件的优先级,SPLASH_URL是splash部署的端口地址。

更详细的使用说明可以参考教程

配置好后,既可以使用splash来渲染页面然后再爬取,需要将scrapy.Request更换为SplashRequest

from scrapy_splash import SplashRequest

image.png

此时在执行

 scrapy crawl login

image.png

可以看到成功爬取到渲染后的数据

登陆鉴权

这篇文章介绍了常见的登陆鉴权和爬虫模拟登陆的方式。

在前面一节我们已经成功得到了渲染后的页面数据,但有些数据需要登陆后才能获得。

这里我们简单介绍一下Cookie结合scrapy框架模拟登陆的方法. setting.py中增加以下配置

COOKIES_ENABLED = True

F12登陆账户后获取你的cookie信息

image.png

def start_requests(self):
    cookiestr = "你的cookie"
    cookies = {i.split("=")[0]: i.split("=")[1] for i in cookiestr.split("; ")}
    yield SplashRequest(url=self.start_urls[0], cookies=cookies,callback=self.parse)

image.png

def parse(self, response):
    time = response.xpath(
        '///html/body/div[3]/div/div/div[1]/strong/a/text()').extract_first()
    print("res:", time)

先换个xpath获取一下用户名

image.png

可以看到获取成功了,这种方式可以用来模拟登陆。

但是在获取上一节通知时间的数据时,虽然模拟成功,但由于它是利用ajax异步去post另一个页面获取数据的,那个post并没有带上我们发过去的cookie,所以没能获取到数据,但可以直接利用cookie访问图上这个url获取数据。

image.png

image.png 这个图可以看到我们的cookie是让我么模拟登陆成功了的,但是没能拿到异步获取的数据。

至于怎么才能让页面异步获取时也带上我们这个cookie,还需要再深入看一下,有懂的大佬可以评论区教一下