【爬虫】实验项目一:文本反爬网站的分析和爬取

目录

一、实验目的

二、实验预习提示

​编辑

三、实验内容

 四、实验要求

 五、实验过程

1. 基本要求:

2. 改进要求A

3. 改进要求B:

六、资料

1.实验框架代码:

2.OpenSSL:Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions (slproweb.com)

3.Josn存储,先安装json包:

4.实验小提示

七、源码


一、实验目的

        熟悉使用Selenium、Pyppeteer等工具爬取网站基本内容,通过分析具有文本反爬技术网站,设计爬取策略来获取文本正确的内容。


二、实验预习提示

  • 安装Python环境 (Python 3.x):Pychram+Anaconda
  • 为Python安装Selenium、PyQuery库(打开pycharm新建项目,选择Anaconda创建的Python环境,在下面对应Console窗口执行):
pip install selenium
pip install pyquery
  • 安装Chrome和对应ChromeDriver:

        下载安装完后查看Chrome版本:点击 Chrome 的菜单,帮助 -> 关于 Chrome,即可查看 Chrome 的版本号105.0.5195.127,如图所示:

 在ChromeDriver 官方网站ChromeDriver - WebDriver for Chrome - Downloads (chromium.org)下载Chrome版本对应的驱动(105.0.5195.x, 看主版本号105都行),点击下划线的链接,根据系统型号下载。windows下chromedriver_win32.zip,其他系统找到对应版本下载:

下面这部分配置环境变量内容【到图片结束(包含图片)】可以省略,参考最新内容【爬虫】5.2 Selenium编写爬虫程序_即使再小的船也能远航的博客-CSDN博客

 运行代码前配置系统环境变量Path前指定chrome driver位置:

Path=替换为chrome driver解压后的位置

或者在Pycharm运行配置指定:


三、实验内容

爬取网站:Scrape | Book

使用浏览器开发者工具(F12),分析网站结构和其中文本反爬机制,编码实现获取该网站每本书的封面图片URL、书名和作者信息。实验基框架代码见文档末资料。


 四、实验要求

        基本要求将网站一页每本书的信息保存在一个josn文件中,每个json文件命名为:书名.json,其内容为保存书籍相应的信息:

{"title": "Wonder","cover_url":"https://img1.doubanio.com/view/subject/l/public/s27252687.jpg","authors":"R. J. Palacio"
}

        实现方法不一定要用Selenium、Pyppeteer,但是必须是Python编写的,并以完成实验要求为准,并附上代码运行结果。

        改进要求A在完成基本要求的基础上,选项一:实现可以遍历网站的每一页来爬取书籍信息。或指定爬取条目数量,当爬取总条目满足数量后停止爬取。选项二:或者举例至少三个其他网站的文本爬虫技术,分析并给出解决方案,不需要实现。

        改进要求B在完成改进要求A的选项一的基础上,可以爬取书籍的额外信息,如评分,出版时间,出版社,ISBM, 价格等。


 五、实验过程

1. 基本要求:

        想要爬取网页内容,首先得分析网页结构,查看源代码如下图所示,

  • 点击封面有对应该书得二级页面(详情)后半部分地址(改进要求B用);
  • 书的封面URL可以用img.class查询;
# 获取书籍封面图片url
for tag in soup.select("img.cover"):pics.append(tag.attrs['src'])
  • 书名都在h3标题中,如果是英文书名,直接h3.name即可,但中文书名由多个class="char"的SPAN元素组成,这里用到了文本反爬机制,利用CSS控制文本偏移来实现文本顺序改变。但不难发现其文本偏移由left属性决定原文正确顺序,因此需要按偏移left属性值大小升序排序获取正确的文本顺序。
# 获取书籍名字
for tag in soup.select("h3.name"):if "whole" in tag.attrs['class']:names.append(tag.text)else:chars = tag.select("span.char")chars = sorted(chars, key=lambda a: eval(a.attrs['style'][6:-3]))name = ""for char in chars:name += char.text.strip()names.append(name)
  • 作者可以直接p.class查询
# 获取作者名字
for tag in soup.select("p.authors"):authors.append(tag.text.strip().replace(" ", "").replace("\n", ""))

2. 改进要求A

        这里实现的是选项一:实现可以遍历网站的每一页来爬取书籍信息。从游览器url: https://antispider3.scrape.center/page/2 得之每页都是在后边加/page/页数,这不难实现,就是写个文本数字追加到url后即可;

url = "https://antispider3.scrape.center/page/"
page_start = int(input("请指定爬取起始页(包含该页):"))
page_end = int(input("请指定爬取结束页(不包含该页):"))
for i in range(page_start, page_end):names, pics, authors, links = get_cover(url + str(i))

         指定爬取条目数量,当爬取总条目满足数量后停止爬取,这个就是在循环爬取写个计数器,爬取到指定数目,break即可,但只得注意的是:指定数量超过一页18条时,继续下一页爬取,也可以直接加在上述代码里,把结束页可以给的很大,用计数器break即可,不会造成伪死循环。

3. 改进要求B:

        从上图页面分析得知:每本书得二级页面都是在https://antispider3.scrape.center后加/detail/数字,该部分网址在a标签得href属性里,由于页面里超链接很多,所以先find_all出div下的class=el-col el-col-24,这里用得class_是为了解决class是python中的关键字问题,爬取后与原始url拼接即可。

# 获取每本书对用url(二级页面)
tags = soup.find_all('div', class_='el-col el-col-24')
print(len(tags))
for tag in [tags[i] for i in range(len(tags)) if i % 2 == 0]:link = tag.find('a').get('href')links.append(url1 + link)
print(links)

        现在得到了每本书得二级页面得url,就可以分析二级页面页面结构,来爬取相应书籍信息,分析如下所示:

         二级页面结构其实还是清新明了的,出了评分时span标签,再其他都是p标签,这里只爬取了上图标注的信息数据,再爬取其他的都是一样的,换汤不换药,其实就换个class就OK,这里不做过多介绍。

         由于爬取页面过多,发现问题:有些书籍没有出版社,页数等,所以这里统一用None,没有的数据就用统一添加该字段去空即可,如做特殊处理,识别没有的信息,每个属性都要增加相同的代码,代码冗余度太高,学术水平限制,这里没想到其他好的方法,所以没有做特殊处理。爬取下来的数据由于中间有很多空格与\n,如下所示

        这里就用到77行一系列的替换,使达到想要的格式,其他类似。

        下面介绍主函数部分:

        这里将每本书的二级页面的url赋给对应属性

for link in links:print(link)score, price, publishtime, publisher, page, isbm = get_details(link)

        这里遍历出每本书的信息保存在以书名为名称的json文件中。

for i in range(len(names)):book = {"title": names[i],"cover_url": pics[i],"authors": authors[i],"link": links[i],"score": scores[i],"price": prices[i],"publish_time": publishtimes[i],"publishers": publishers[i],"pages": pages[i],"ISBM": isbms[i]}data_path = f'{book["title"]}.json'json.dump(book, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)

        最后附上爬取结果:

 本次实现总结:

        计算机专业的课程只理论不实践那就例如纸上谈兵,本次实践说简单也不难,但有些点还是触及我的知识盲区了,例如span char的书名,实践是检验真理的唯一标准。爬虫技术有限,每次爬二级页面都要加载打开,很浪费时间的,后期学了更多的知识,再来解决此问题吧。


六、资料

1.实验框架代码:

from selenium import webdriver
from pyquery import PyQuery as pq
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
browser = webdriver.Chrome()
browser.get('https://antispider3.scrape.center/')
WebDriverWait(browser, 10) \.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.item')))
html = browser.page_source
doc = pq(html)
names = doc('.item .name')
for name in names.items():print(name.text())

2.OpenSSL:Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions (slproweb.com)

3.Josn存储,先安装json包:

import jsonbook = {"title": "Wonder","cover_url":"https://img1.doubanio.com/view/subject/l/public/s27252687.jpg","authors":"R. J. Palacio"}data_path = f'{book["title"]}.json'
json.dump(book, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)

4.实验小提示

        可以根据HTML结构发现每个书籍信息都保存在。有的书名放在class="name whole"的H3元素,有书名由多个class="char"的SPAN元素组成。对于放在H3元素的书名,直接取出其元素内容即可,而对于放在多个SPAN元素中的书名,这里用到了文本反爬机制,利用CSS控制文本偏移来实现文本顺序改变。但不难发现其文本偏移由left属性决定原文正确顺序,因此需要按偏移left属性值大小升序排序获取正确的文本顺序。


七、源码

import json
import warnings
from selenium import webdriver
from pyquery import PyQuery as pq
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from bs4 import BeautifulSoup# 定义容器用来存储书籍的信息
names = []  # 书籍名字
authors = []  # 书籍作者
pics = []  # 书籍封面图片
links = []  # 链接
scores = []  # 评分
prices = []  # 定价
publishtimes = []  # 出版时间
publishers = []  # 出版社
pages = []  # 页数
isbms = []  # ISBM# 获取书籍分面信息与对应书籍二级页面url
def get_cover(url):warnings.filterwarnings('ignore')browser = webdriver.Chrome()browser.get(url)WebDriverWait(browser, 10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.item')))html = browser.page_sourcedoc = pq(html)# 使用BeautifulSoup进行解析网页soup = BeautifulSoup(doc.html(), "html.parser")browser.close()# 获取书籍名字for tag in soup.select("h3.name"):if "whole" in tag.attrs['class']:names.append(tag.text)else:chars = tag.select("span.char")chars = sorted(chars, key=lambda a: eval(a.attrs['style'][6:-3]))name = ""for char in chars:name += char.text.strip()names.append(name)# 获取作者名字for tag in soup.select("p.authors"):authors.append(tag.text.strip().replace(" ", "").replace("\n", ""))# 获取书籍封面图片urlfor tag in soup.select("img.cover"):pics.append(tag.attrs['src'])# 获取每本书对用url(二级页面)tags = soup.find_all('div', class_='el-col el-col-24')print(len(tags))for tag in [tags[i] for i in range(len(tags)) if i % 2 == 0]:link = tag.find('a').get('href')links.append(url1 + link)print(links)return names, pics, authors, links# 获取每本书的详细信息(二级页面信息)
def get_details(url):warnings.filterwarnings('ignore')browser = webdriver.Chrome()browser.get(url)WebDriverWait(browser, 300).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.item')))html = browser.page_sourcedoc = pq(html)# 使用BeautifulSoup进行解析网页soup = BeautifulSoup(doc.html(), "html.parser")# 获取评分score = soup.find('span', class_='score m-r m-b-sm')if score != None:score = score.textscore = str(score).replace(' ', '').replace('\t', '').replace('\n', '')else:score = ' 'scores.append(score)# 获取定价price = soup.find('p', class_='price')if price != None:price = price.textprice = str(price).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]else:price = ' 'prices.append(price)# 获取出版时间publishtime = soup.find('p', class_='published-at')if publishtime != None:publishtime = publishtime.textpublishtime = str(publishtime).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]else:publishtime = ' 'publishtimes.append(publishtime)# 获取出版社publisher = soup.find('p', class_='publisher')if publisher != None:publisher = publisher.textpublisher = str(publisher).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]else:publisher = ' 'publishers.append(publisher)# 获取页数page = soup.find('p', class_='page-number')if page != None:page = page.textpage = str(page).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]else:page = ' 'pages.append(page)# 获取ISBMisbm = soup.find('p', class_='isbn')if isbm != None:isbm = isbm.textisbm = str(isbm).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]else:isbm = ' 'isbms.append(isbm)browser.close()return score, price, publishtime, publisher, page, isbmif __name__ == '__main__':url1 = "https://antispider3.scrape.center"url = "https://antispider3.scrape.center/page/"page_start = int(input("请指定爬取起始页(包含该页):"))page_end = int(input("请指定爬取结束页(不包含该页):"))for i in range(page_start, page_end):names, pics, authors, links = get_cover(url + str(i))for link in links:print(link)score, price, publishtime, publisher, page, isbm = get_details(link)for i in range(len(names)):book = {"title": names[i],"cover_url": pics[i],"authors": authors[i],"link": links[i],"score": scores[i],"price": prices[i],"publish_time": publishtimes[i],"publishers": publishers[i],"pages": pages[i],"ISBM": isbms[i]}data_path = f'{book["title"]}.json'json.dump(book, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)

下一篇文章: 实验项目二:模拟登录和数据持久化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/61747.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Node与Express后端架构:高性能的Web应用服务

在现代Web应用开发中,后端架构的性能和可扩展性至关重要。Node.js作为一个基于事件驱动、非阻塞I/O的平台,以及Express作为一个流行的Node.js框架,共同构建了高性能的Web应用服务。 在本文中,我们将深入探讨Node与Express后端架构…

Windows笔记本电脑开机黑屏

Windows笔记本电脑开机黑屏 最近,我遇到了一件奇怪的事情。我的Windows笔记本电脑在开机时出现了一个黑屏,没有任何反应。我尝试了多种方法,包括重启和恢复出厂设置,但都无济于事。 我开始感到担心,因为这只会影响到…

污水厂数字孪生 | 3D可视化管理系统助力污水企业数字化管理

随着城市化进程的不断加快,污水处理成为了城市环境保护的重要组成部分。传统的污水处理方式往往存在诸多问题,如信息不对称、安全隐患等。为了解决这些问题,污水处理3D可视化管控平台应运而生,它通过结合数字孪生技术和远程指导技…

【行为树】py_trees 学习笔记

学习资料 《Introduction to behavior trees》 1. 概念说明 1.1 Action:pt.behaviour.Behaviour 在一个行为树中,Action 是一个叶节点(Leaf Node),它实际执行某种行为或任务,并返回成功、失败或运行中的…

Unity关键概念

Unity是一款跨平台的游戏引擎和开发工具,用于创建2D和3D游戏、交互式内容和应用程序。它提供了一个强大的开发环境,使开发者能够轻松地设计、开发和部署高质量的游戏和应用程序。 以下是Unity的几个关键概念: 游戏对象(Game Obj…

【逻辑运算符】在Java中 和的区别 ||和|的区别

&&和&都表示与运算符,结果为有假则假,&&为短路与运算符,如果表达式A的值为假,则表达式B不执行;&表示逻辑与运算符,表达式A和表达式B都会执行 ||和|都表示或运算符,结果为有真则真&…

C# 静态构造函数未执行 .net core框架

代码如下&#xff0c;在执行Encoding.GetEncoding(“gb2312”);方法后报错&#xff0c;说没有找到对应编码&#xff0c;经测试&#xff0c;发现是静态构造函数未执行。 public static class Encodings {/// <summary>/// 注册相关编码/// </summary>static Encodi…

SpringBoot整合Freemaker结合Vue实现页面填写一键自动生成Redis的配置文件

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 &#x1f4d6;所属专栏&#xff1a;Sp…

【Android】使用 adb 命令行工具结合 pm列出 Android 设备上已安装应用的应用名称和包名

要列出 Android 设备上已安装应用的应用名称和包名&#xff0c;你可以使用 adb 命令行工具结合 pm&#xff08;PackageManager&#xff09;命令来实现。 首先&#xff0c;确保你已经安装了 Android SDK&#xff0c;并将 adb 工具添加到系统的环境变量中。 然后&#xff0c;打…

Linux 管道(pipe)用法

在 Linux 中&#xff0c;管道&#xff08;pipe&#xff09;是一种特殊的机制&#xff0c;用于连接一个进程的标准输出到另一个进程的标准输入。通过使用管道&#xff0c;可以将一个命令的输出直接传递给另一个命令进行处理&#xff0c;实现了进程之间的通信和数据传输。 管道的…

基于“互联网+ 服务供应链”的汽车道路救援系统对策分析

1。 建立“互联网服务供应链”背景下汽车道路救援系统 基于互联网的汽车道路救援&#xff0c;两级服务供应链结构是由服务提供商、服务 集成商和客户组成。“互联网服务供应链”背景下汽车道路救援系统组成&#xff0c; 它是一种 B2B2C 的形式&#xff0c;与前述传统汽车道路…

管理类联考——逻辑——形式逻辑——汇总篇——知识点突破——假言——各种假言

角度 多重假言 &#xff08;1&#xff09;如果A&#xff0c;那么B&#xff0c;除非C。 符号化为&#xff1a;┐C→ (A→B)。 等价于&#xff1a;┐C→ (┐A∨B)。 等价于&#xff1a;C∨(┐A∨B)。 等价于&#xff1a;C∨┐A∨B。 等价于&#xff1a;┐(C∨┐A&#xff09;→…

035 - datetime和timedstamp

该DATETIME类型用于包含日期和时间部分的值。MySQL检索并DATETIME以格式显示 值 。支持的范围是 到。 YYYY-MM-DD hh:mm:ss1000-01-01 00:00:009999-12-31 23:59:59 该TIMESTAMP数据类型被用于同时包含日期和时间部分的值。 UTCTIMESTAMP的范围是UTC。 1970-01-01 00:00:01203…

039 - sql逻辑操作符

前提&#xff1a; 做两个表employee和movie&#xff0c;用来练习使用&#xff1b; 表一&#xff1a;employee -- 创建表employee CREATE TABLE IF NOT EXISTS employee(id INT NOT NULL AUTO_INCREMENT,first_name VARCHAR(100) NOT NULL,last_name VARCHAR(100) NOT NULL,t…

软件工程(七) UML之用例图详解

1、UML-4+1视图 UML-4+1视图将会与后面的架构4+1视图会一一对应上 视图往往出现在什么场景:我们看待一个事物,我们觉得它很复杂,难以搞清楚,为了化繁为简,我们会从一个侧面去看,这就是视图。而4+1视图就是分不同角度去看事物。 逻辑视图(logical view) 一般使用类与对…

素数之谜揭秘:一文详解试除法判断素数

这是我非常喜欢的一道编程题目。不要小看这道题&#xff0c;它看似简单&#xff0c;实则奥妙无穷。由于这是C语言的入门篇&#xff0c;只介绍最简单&#xff0c;也最容易想到的方法&#xff1a;试除法。但哪怕是试除法&#xff0c;也有不少变化。 要想了解试除法&#xff0c;首…

软件测试人需要掌握的测试知识架构体系(上)

软件计划与可行性研究&#xff08;问题定义、可行性研究&#xff09;&#xff1b;需求分析&#xff1b;软件设计&#xff08;概要设计、详细设计&#xff09;&#xff1b;编码&#xff1b;软件测试&#xff1b;运行与维护。 一、软件的生命周期(SDLC) 1、生存周期划分 各阶段…

软件测试/测试开发丨Selenium 高级定位 Xpath

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27036 一、xpath 基本概念 XPATH是一门在XML文档中查找信息的语言 XPATH使用路径表达式在XML文档中进行导航 XPATH的应用非常广泛&#xff0c;可以用于UI自…

RT-Thread 线程管理(一)

线程管理 在日常生活中&#xff0c;要完成一个大任务&#xff0c;一般会将它分解成多个简单、容易解决的小问题&#xff0c;小问题逐个被解决&#xff0c;大问题也就随之解决了。 在多线程操作系统中&#xff0c;也同样需要开发人员把一个复杂的应用分解成多个小的、可调度的…