爬取动态渲染网站scrapy接入splash

scrapy结合scrapy-splash

scrapy-splash 的安装

windows下安装并启动
# 拉取splash
docker pull scrapinghub/splash
# 运行splash 
docker run -p 8050:8050 --name splash scrapinghub/splash
docker run -itd --name splash  -p 8050:8050 scrapinghub/splash --disable-lua-sandbox  bash
docker run -itd --name splash  -p 8050:8050 scrapinghub/splash bash
# 宿主机网络
docker run -itd --name splash  -p 8050:8050 --network=host scrapinghub/splash bash
# -p 向外暴露端口
# -d 守护进程方式运行(后台运行)
# --name 自定义昵称
# --disable-lua-sandbox 关闭沙盒模式。如果是在测试环境上可以直接去体验一下,功能更全。如果是在开发环境的话那就直接用正式的,虽然花里胡哨,但安全性并不好

进入容器
docker exec -it [容器名] bash

kill所有容器进程
docker kill $(docker ps -a -q)
delete所有容器
docker rm $(docker ps -a -q) 
执行容器,传递环境变量 -e
docker run -itd --name splash -e http_proxy="127.0.0.1:10809" -e https_proxy="127.0.0.1:10809" -p 8050:8050 scrapinghub/splash bash

需要访问谷歌等网站

执行容器,传递环境变量 -e
docker run -itd --name splash -e http_proxy=127.0.0.1:10809 -p 8050:8050 scrapinghub/splash bash
或者
进入容器
docker exec -it [容器名] bash
export http_proxy=127.0.0.1:10809

问题:localhost:port无法访问,但在容器内 curl 可以访问


无法访问 splash,windows下可能是因为访问地址ip有问题

docker是运行在Linux上的,在Windows中运行docker,实际上还是在Windows下先安装了一个Linux环境,然后在这个系统中运行的docker
docker-machine ip default
显示 docker 机器的默认ip,一般是 192.168.99.100

https://github.com/Dreamacro/clash/releases/tag/v1.14.0

scrapy集成 scrapy-splash

pip安装

pip3 install scrapy-splash

项目 settings 配置

# splash
SPLASH_URL = 'http://192.168.99.100:8050'
DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

代码中使用 SplashRequest 类

from scrapy_splash import SplashRequest
# 原本是yield Request()
yield SplashRequest()
yield SplashRequest(url, headers=headers, dont_filter=True)

命令行访问谷歌

windows 用 cmd 的 curl

set http_proxy=127.0.0.1:1080
set https_proxy=127.0.0.1:1080

全局配置

设置环境变量 HTTP_PROXY HTTPS_PROXY
### 解决 Scrapy 中 'NoneType' 对象错误并成功爬取 1905 网站 在使用 Scrapy 爬取网站时,如果遇到 `AttributeError: 'NoneType' object has no attribute 'xpath'` 或 `'css'` 错误,通常是因为尝试对一个无效或未匹配的选择器调用了方法。以下是解决此问题的详细分析和解决方案。 #### 1. 确保请求返回有效响应 在爬取 1905 网站或其他目标网站时,首先需要确保请求成功且返回了有效的 HTML 内容。可以通过检查 `response.status` 和 `response.body` 来验证请求是否成功[^2]。 ```python def parse(self, response): if response.status != 200: self.logger.error(f"Failed to fetch page {response.url}, status code: {response.status}") return ``` #### 2. 验证选择器路径 如果选择器路径不正确,可能会导致提取的数据为 `None`,从而引发错误。建议在 Scrapy Shell 中测试选择器表达式以确保其正确性[^3]。 ```bash scrapy shell "http://www.1905.com" ``` 在交互式环境中测试 XPath 或 CSS 选择器: ```python # 测试 XPath response.xpath('//div[@class="example-class"]/text()').get() # 测试 CSS 选择器 response.css('div.example-class::text').get() ``` #### 3. 处理嵌套选择器 当使用嵌套选择器时,如果外层选择器未匹配到任何内容,则内层选择器将基于 `None` 对象调用,从而引发错误。确保每次调用前验证外层选择器的结果[^1]。 ```python outer = response.xpath('.//ul') if outer: inner = outer.css('li').xpath('./text()') for item in inner: print(item.get()) ``` #### 4. 使用 `.get()` 或 `.extract()` 方法 `SelectorList` 对象的 `.get()` 方法返回单个值,而 `.extract()` 方法返回列表。如果选择器未匹配到任何内容,`.get()` 将返回 `None`,而 `.extract()` 返回空列表[^1]。 ```python title = response.css('h1.title::text').get() # 返回单个值或 None titles = response.css('h1.title::text').extract() # 返回列表或空列表 ``` #### 5. 检查 Request 是否正确生成 如果 `start_requests` 方法未正确生成请求,可能导致 `parse` 方法接收到的 `response` 为 `None`。确保 `start_requests` 方法正确实现。 ```python def start_requests(self): headers = {'User-Agent': 'Mozilla/5.0'} for url in self.start_urls: yield scrapy.Request(url, headers=headers, callback=self.parse) ``` --- ### 示例代码:爬取 1905 网站 以下是一个完整的 Spider 示例,展示如何避免 `NoneType` 错误并成功爬取 1905 网站的内容: ```python import scrapy class MovieSpider(scrapy.Spider): name = 'movie' start_urls = ['http://www.1905.com'] def parse(self, response): if response.status != 200: self.logger.error(f"Failed to fetch page {response.url}, status code: {response.status}") return items = response.css('div.item') # 假设页面中有多个 item 元素 for item in items: title = item.css('h2.title::text').get() # 提取标题 link = item.css('a::attr(href)').get() # 提取链接 if title and link: # 确保数据不为空 yield { 'title': title, 'link': link } ``` --- ### 注意事项 - 在爬取 1905 网站时,请确保遵守其 robots.txt 文件中的规则,并设置合理的请求间隔以避免对服务器造成过大压力。 - 如果目标网站使用动态加载技术(如 JavaScript 渲染),可能需要结合 Selenium 或其他工具来处理动态内容[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值