问题描述

一些网站会有很多的重定向,才能跳转到真实的资源页。然后爬虫就会报错:requests.exceptions.TooManyRedirects: Exceeded 30 redirects.
这种情况,可以直接关掉重定向,判断响应状态是301或302然后手动重定向。
参考:Python Requests:TooManyRedirects问题解决

在手动重定向后,我又遇到了异步加载的问题。
爬取得到的页面只有“加载中”,没有实际内容。

出问题的网页是:常用来爬虫的某网站
爬取之后得到的就只有这个:

查看网页,可以看到数据是靠浏览器运行JS脚本异步加载的,这时候必须要浏览器渲染,网页的内容才会显示出来。

我查到两种解决方式,一是分析源码,然后想办法自己渲染一下;二是使用requests-html,它提供了render渲染、提供了html异步解析。

requests-html表面上看起来非常不戳啊,好像啥都有了,可是问题是它和requests是同一个作者,requests直到今天还在更新,而requests-html两年没更新了,怎么看都是个天坑吧

那,要不结合浏览器,咱给它模拟渲染一个吧?

默默捡起了我好久没用的Selenium。
果然,兜兜转转,还是逃不过写模拟吗?

我的版本:

requests           2.27.1
selenium 4.2.0
Edge 102.0.1245.44

1. 结合Selenium、Edge解析该网站搜索页面的数据

首先,用Selenium需要下载个浏览器模拟驱动:selenium官网

选个自己常用的浏览器就完事了。我选的是Edge。
注意:和自己的电脑中的浏览器版本要一致。

使用Selenium的时候遇到了以下问题:

  1. RequestsDependencyWarning: urllib3 (1.26.9) or chardet (3.0.4) doesn‘t match a supported version
    解决:更新requests:pip3 install --upgrade requests
  2. DeprecationWarning: executable_path has been deprecated, please pass in a Service object
    解决:出现 DeprecationWarning 警告的类型错误:该类型的警告大多属于版本已经更新,所使用的方法过时。查询当前版本重构后的函数,是之前的 executable_path 被重构到了 Service 函数里。所以,新版的selenium不能继续用executable_path,而是应该写成Service。解决方式参考:https://blog.csdn.net/qq_43472877/article/details/121097672
  3. 打开了浏览器,但是没有显示网页。调试后发现Service连接失败。这是因为浏览器驱动下载错误。浏览器驱动下载网址:selenium官网
  4. invalid argument: invalid locator
    (Session info: MicrosoftEdge=102.0.1245.44)
    解决:这有三种原因:
    ①浏览器版本和驱动版本不一致(请在设置里查看自己的浏览器版本,然后在上面说的浏览器驱动下载网址那儿下自己的版本);
    ②没有sleep;(新版的selenium已经可以不sleep了,不会闪退,程序跑完了才会自动退出)
    代码打错了。比如edge.find_elements(by="//div"),正确的是edge.find_elements(by='xpath',value="//div")

一个超简单的能正常运行的selenium程序如下:

from selenium import webdriver
from selenium.webdriver.edge.service import Service
import requests
from time import sleep s = Service('./edgedriver_win64/msedgedriver.exe')
edge = webdriver.Edge(service=s)
edge.get("https://movie.douban.com/subject_search?search_text=花束般的恋爱")
# requests库,构造会话
session = requests.Session()
# 获取cookies
cookies = edge.get_cookies()
# 填充
for cookie in cookies:
session.cookies.set(cookie['name'], cookie['value']) # 给网页留一点加载的时间,不然之后find不了元素
sleep(2)
detail = edge.find_elements(by='xpath', value="//div[@class='detail']")
for i in range(0, len(detail)):
title = detail[i].find_element(by='xpath', value="./div[@class='title']")
rating_nums = detail[i].find_elements(by='xpath', value="./div/span[@class='rating_nums']")
title_a = detail[i].find_element(by='xpath', value="./div[@class='title']/a").get_property('href')
if (len(rating_nums) == 0):
print(i, title.text, '暂无评分', title_a)
else:
print(i, title.text, rating_nums[0].text, title_a)
if (i >= 5): # 最多显示6个结果就行
break

我把常用的xpath相关的、selenium相关的都尽可能在上述代码中写到了。
这对于学习来说,应该是一个很好的例子。
比如get_property是获取元素的属性。
比如xpath中的“目录”层次,./div[@class='title'](其实和电脑的文件系统的目录结构是一样的,多看看就会发现这东西好简单的)。
比如find_elementsfind_element的区别。

注意:当页面中没有find_element能够找到的元素的时候,它就会直接抛出异常“invalid Locator”,而不是返回空。
所以不能确定到底有没有的时候只能用find_elements

给大家表演一个实际效果~

2. 结合lxml解析网页数据

selenium的xpath语法写得没有lxml的简洁,我之前一直用的是lxml解析网页。
selenium得到的网页→网页文本→用lxml做元素分析,(很容易);
网页文本→selenium的类,(很难);
所以我的建议是:干脆一直用lxml库做网页文本的解析,这样更通用些,而且代码量小很多很多

给大伙看一下selenium和lxml的对比(上面是selenium,下面是lxml):

detail = edge.find_elements(by='xpath', value="//div[@class='detail']")
for i in range(0, len(detail)):
title = detail[i].find_element(by='xpath', value="./div[@class='title']")
rating_nums = detail[i].find_elements(by='xpath', value="./div/span[@class='rating_nums']")
title_a = detail[i].find_element(by='xpath', value="./div[@class='title']/a").get_property('href')
if (len(rating_nums) == 0):
print(i, title.text, '暂无评分', title_a)
else:
print(i, title.text, rating_nums[0].text, title_a)
if (i >= 5): # 最多显示6个结果就行
break

下面是lxml:

from lxml import etree
html=etree.HTML(edge.page_source) # 没错!只要加上一行!就可以丝滑地转换成lxml
detail = html.xpath("//div[@class='detail']")
for i in range(0, len(detail)):
title = detail[i].xpath("./div[@class='title']/a/text()")
rating_nums = detail[i].xpath("./div/span[@class='rating_nums']/text()")
title_a = detail[i].xpath("./div[@class='title']/a/@href")
if (len(rating_nums) == 0):
print(i, title[0], '暂无评分', title_a[0])
else:
print(i, title[0], rating_nums[0], title_a[0])
if (i >= 5): # 最多显示6个结果就行
break

运行结果和上面那个程序是一样的哈:

3. 附加:不是异步加载的网页,结合requests直接请求数据

上面那个程序是直接读selenium的网页内容,用的是find_elements之类的。而且每次读都要打开网页、等待加载,这其实挺繁琐的。

对于不是异步加载的网页,只要个url,就可以用requests来请求了。

请求方式有好几种:requests.getrequests.postsession.get等。

常用前两种,但是我后来发现session的bug少一点:网页反复重定向的时候,据说用session会话请求就不会丢失headers的内容。

session只是多一个步骤罢了。例如:

import requests
headers = {}
sessions = requests.session() # 就多这一个步骤
sessions.headers = headers
r = sessions.get(url, headers = headers)

我写了个比较通用的请求数据的函数,返回的是reslxml解析的html
有需要的话可以抱走:

from lxml import etree
def getData(url):
while (1):
res = session.get(url, headers=headers)
if (res.status_code == requests.codes.ok):
content = res.text
html = etree.HTML(content)
return res, html
elif (res.status_code == 302 or res.status_code == 301):
print(url + " --重定向到--> " + res.headers["Location"])
url = res.headers["Location"]
else:
print("出问题啦!", res.status_code)
cookieChange = int(input("是否更换Cookie(输入1或0):"))
if (cookieChange):
headers['Cookie'] = input("请输入Cookie:")
sleep(5)

本账号所有文章均为原创,欢迎转载,请注明文章出处:https://blog.csdn.net/qq_46106285/article/details/125416641。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

【笔记】Python爬虫|网页数据异步加载(结合Selenium完成)的更多相关文章

  1. Python爬虫爬取异步加载的数据

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.作者:努力努力再努力 爬取qq音乐歌手数据接口数据 https://y.qq ...

  2. Python 爬虫练习项目——异步加载爬取

    项目代码 from bs4 import BeautifulSoup import requests url_prefix = 'https://knewone.com/discover?page=' ...

  3. Python爬虫之JS异步加载

    一.判断异步加载方式(常用的JS库) 1. jQuery(70%) # 搜索 jquery 茅塞顿开 <script src="http://ajax.googleapis.com/a ...

  4. python爬虫之图片懒加载、selenium和phantomJS

    一.什么是图片懒加载 在网页中,常常需要用到图片,而图片需要消耗较大的流量.正常情况下,浏览器会解析整个HTML代码,然后从上到下依次加载<img src="xxx"> ...

  5. Java 爬虫遇上数据异步加载,试试这两种办法!

    这是 Java 爬虫系列博文的第三篇,在上一篇 Java 爬虫遇到需要登录的网站,该怎么办? 中,我们简单的讲解了爬虫时遇到登录问题的解决办法,在这篇文章中我们一起来聊一聊爬虫时遇到数据异步加载的问题 ...

  6. Android学习笔记_36_ListView数据异步加载与AsyncTask

    一.界面布局文件: 1.加入sdcard写入和网络权限: <!-- 访问internet权限 --> <uses-permission android:name="andr ...

  7. android的progressDialog 的使用。android数据异步加载 对话框提示

    在调用的Activity中定义一个全局的 progressDialog 点击按钮的时候调用下面这句 progressDialog = ProgressDialog.show(SearchActivit ...

  8. vue-awesome-swiper中的数据异步加载

    <template> <div> //第一个轮播 加了v-if 判断,可以实现 loop 轮循 <swiper v-if="gglist.length>1 ...

  9. android 数据异步加载

    public class MainActivity extends Activity { ListView listView; File cache; //访问其他线程在当前线程中存放的数据 Hand ...

  10. Android学习笔记(二)之异步加载图片

    最近在android开发中碰到比较棘手的问题,就是加载图片内存溢出.我开发的是一个新闻应用,应用中用到大量的图片,一个界面中可能会有上百张图片.开发android应用的朋友可能或多或少碰到加载图片内存 ...

随机推荐

  1. 【整活向】把tidb的文档塞给了基于oceanbase的RAG机器人

    最近官方推出了免费试用365天的云数据库,版本也升级到了4.3.支持了向量功能. 官方推出了活动体验AI的动手实战活动, 教程中使用了docker单机版数据库,既然有免费的云数据库,就优先使用云数据库 ...

  2. [ARC148C] Lights Out on Tree 题解

    在考场遇到了这道题,感觉很有意思. 当时直接想到的就是虚树,可惜打挂了. 后来改对了,写篇题解纪念一下. 首先看到 \(\sum M_i\le 2\times 10^5\),很容易想到虚树的数据范围. ...

  3. Forest v1.5.13 发布,声明式 HTTP 框架,已超 1.8k star

    Forest介绍 Forest 是一个开源的 Java HTTP 客户端框架,它能够将 HTTP 的所有请求信息(包括 URL.Header 以及 Body 等信息)绑定到您自定义的 Interfac ...

  4. job提交后,inp文件的处理过程

    用户提交job后,abaqus的inp文件处理过程 1. 对inp文件预处理 打开任务管理器可以看到pre.exe的进程 预处理中的error .warning 都会在.DAT文件中 dat文件出现e ...

  5. ITIL4 变更管理核心流程笔记

  6. kubectl port-forward bind: address already in use unable

    前言 本地的 8080 映射到 Pod 的 80,kubectl 会把这个端口的所有数据都转发给集群内部的 Pod kubectl port-forward wp-pod 8080:80 & ...

  7. Mqtt集成与设计

    Mqtt集成 集成mqtt,我们首先得明白什么是mqtt: MQTT(Message Queuing Telemetry Transport)是一种轻量级.基于发布-订阅模式的消息传输协议,适用于资源 ...

  8. Docker | 如何在 Linux 服务器使用 docker

    目录 00 需求 01 安装 docker 02 准备工作 03 配置 Dockerfile 和 docker composer 04 启动 docker 05 测试能否 ssh 连接这个 docke ...

  9. 使用键盘控制gazebo小车模型运动

    博客地址:https://www.cnblogs.com/zylyehuo/ gazebo小车模型创建详见另一篇博客 博客地址:gazebo小车模型(附带仿真环境) - zylyehuo - 博客园 ...

  10. 基于.NetCore开发 StarBlog 番外篇 (1) StarBlog Publisher,跨平台一键发布,DeepSeek加持的文章创作神器

    前言 我一直在优化发布文章的工作流 之前的 StarBlog 已经支持文章打包上传(将 Markdown 和图片文件一并打包为 ZIP 格式上传),但还是有不少步骤,重复的次数多了,还是感觉麻烦. 为 ...