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

目录

一、实验目的

二、实验预习提示

​编辑

三、实验内容

 四、实验要求

 五、实验过程

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 json

book = {"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_source
    doc = 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", ""))

    # 获取书籍封面图片url
    for 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_source
    doc = 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.text
        score = str(score).replace(' ', '').replace('\t', '').replace('\n', '')
    else:
        score = ' '
    scores.append(score)

    # 获取定价
    price = soup.find('p', class_='price')
    if price != None:
        price = price.text
        price = 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.text
        publishtime = 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.text
        publisher = 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.text
        page = str(page).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]
    else:
        page = ' '
    pages.append(page)

    # 获取ISBM
    isbm = soup.find('p', class_='isbn')
    if isbm != None:
        isbm = isbm.text
        isbm = str(isbm).replace(' ', '').replace('\t', '').replace('\n', '').split(':')[1]
    else:
        isbm = ' '
    isbms.append(isbm)
    browser.close()
    return score, price, publishtime, publisher, page, isbm


if __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)

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu学习---跟着绍发学linux课程记录(第一部分)

文章目录 1、启动、关闭、挂起、恢复(电源)2、更多虚拟机操作2.1 电源设置2.2 硬件参数设置2.3 状态栏2.4 全屏显示 3、快照与系统恢复4、桌面环境5、文件系统6、用户目录7、创建目录和文件8、命令行:文件列表ls 9、命令行:切换目…

Vulnstack----5、ATTCK红队评估实战靶场五

文章目录 一 环境搭建二 外网渗透三 内网信息收集3.1 本机信息收集3.2 域内信息收集 四 横向移动4.1 路由转发和代理通道4.2 抓取域用户密码4.3 使用Psexec登录域控4.4 3389远程登录 五、痕迹清理 一 环境搭建 1、项目地址 http://vulnstack.qiyuanxuetang.net/vuln/detail/7/ …

python读取图像小工具

一、和图像交互获得图像的坐标和像素值 import cv2 import numpy as np import signal import threading import timeif __name__ __main__:img cv2.imread(XXX,0)#读取图片font_face,font_scale,thicknesscv2.FONT_HERSHEY_SIMPLEX,0.5,1#鼠标交互def mouseHandler(event,x…

香港服务器快还是台湾服务器快?

​  基于机房位置不同,香港服务器相对于台湾服务器在访问速度方面有一定的优势。香港服务器拥有CN2线路,因此访问速度较快。在网络服务商方面,中华电信等台湾服务商提供的带宽也具有很高的性价比。 香港服务器对大陆用户的影响 对于大陆用户…

掌握这个工具,轻松管理所有物流信息

在电子商务高度发达的今天,物流快递行业在全球范围内发挥着至关重要的作用。然而,在如此复杂的物流环境中,快递退回件的管理和查询成为了一个难题。为了解决这个问题,我们有一个神奇的工具——快递批量查询高手。 快递批量查询高…

聚观早报|阿维塔完成B轮融资;文心一言向全社会开放

【聚观365】9月1日消息 阿维塔完成B轮融资 文心一言向全社会开放 长安汽车上半年销量超121万辆 北京工人体育场5G超级网络启用 挚文集团Q2净利润5.684亿元 阿维塔完成B轮融资 日前,阿维塔科技宣布完成B轮融资,募集资金30亿元,投后估值近…

在CentOS7中,安装并配置Redis【个人笔记】

一、拓展——Ubuntu上安装Redis 输入命令su --->切换到root用户【如果已经是,则不需要进行该操作】apt search redis --->使用apt命令来搜索redis相关的软件包【查询后,检查redis版本是否是你需要的,如果不是则需要看看其他资料~】ap…

易基因:De novo组装和转录组表征:东方田鼠原发性卵巢癌机制新见解|项目文章

大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。 2022年,中南大学湘雅医学院周智君教授团队在Mol Med Rep发表了题为" De novo assembly and transcriptome characterization: Novel insights into the mechanisms of p…

Linux的内存理解

建议 Mysql机器 尽量不要硬swap,如果是ssd磁盘还好。Free命令 free 命令显示系统内存的使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存 输出简介: Mem 行(第二行)是内存的使用情况。Swap 行(第三行)是交换空间的使用情况。total 列显示系统总的可用物理内存和交换…

Ansible学习笔记3

ansible模块: ansible是基于模块来工作的,本身没有批量部署的能力,真正具有批量部署的是ansible所运行的模块,ansible只是提供一个框架。 ansible支持的模块非常多,我们并不需要把每个模块记住,而只需要熟…

免费OCR图像识别文字识别API

免费OCR图像识别文字识别API 一、OCR图像识别文字识别二、使用步骤1、接口2、请求参数3、请求参数示例4、接口 返回示例 三、温馨提示 一、OCR图像识别文字识别 光学字符识别(Optical Character Recognition, OCR)是指对文本资料的图像文件进行分析识别…

解决legend数据过多,使用滚动,但进行后图形样式发生变化

前言: 滚动前: 滚动后: 滚动前后,饼状图中的内容除了“城市规划”和“城市管理部件”两个分类进行了位置的交换,没有其他的变化,数据也没有增加,但是,样式就是不知道为啥发生了变化。…

[maven]关于pom文件中的<relativePath>标签

关于pom文件中的<relativePath>标签 为什么子工程要使用relativePath准确的找到父工程pom.xml.因为本质继承就是pom的继承。父工程pom文件被子工程复用了标签。&#xff08;可以说只要我在父工程定义了标签&#xff0c;子工程就可以没有&#xff0c;因为他继承过来了&…

趣味微项目:玩转Python编程,轻松学习快乐成长!

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 在学习Python编程的旅程…

web端调用本地摄像头麦克风+WebRTC腾讯云,实现直播功能

目录 关于直播直播流程直播视频格式封装推流和拉流 获取摄像头和麦克风权限navigator.getUserMedia()MediaDevices.getUserMedia() WebRTC腾讯云快直播 关于直播 视频直播技术大全、直播架构、技术原理和实现思路方案整理 直播流程 视频采集端&#xff1a; 1、视频采集&#…

[Spring Boot] 开发时可以运行,但Maven打包后,无法运行

问题&#xff1a;开发过程中一切正常&#xff0c;但在打包后&#xff0c;使用java -jar运行jar包时报错 Exception in thread "main" java.lang.UnsupportedClassVersionError: org/springframework/boot/loader/JarLauncher has been compiled by a more recent ver…

【Latex】使用技能站:(三)使用 Vscode 配置 LaTeX

使用 Vscode 配置 LaTeX 引言1 安装texlive2 安装vscode2.1 插件安装2.2 配置 3 安装SumatraPdf3.1 vscode配置3.2 配置反向搜索 引言 安装texlive 安装vscode 安装SumatraPdf 1 安装texlive 在线LaTeX编辑器&#xff1a;https://www.overleaf.com TeX Live下载&#xff1a;h…

环境异常总结

1.vue项目 npm run dev 运行时报错&#xff1a;webpack-dev-server --inline --progress --config build/webpack.dev.conf.js 不是内部或外部命令 原因&#xff1a;webpack-dev-server存在问题 解决方案&#xff1a;指定 webpack-dev-server 低版本号 方法&#xff1a; 删除 …

Python爬虫-某网酒店数据

前言 本文是该专栏的第5篇,后面会持续分享python爬虫案例干货,记得关注。 本文以某网的酒店数据为例,实现根据目标城市获取酒店数据。具体思路和方法跟着笔者直接往下看正文详细内容。(附带完整代码) 正文 地址:aHR0cHM6Ly93d3cuYnRoaG90ZWxzLmNvbS9saXN0L3NoYW5naGFp …

【LeetCode】84.柱状图中最大的矩形

题目 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heights [2,1,5,6,2,3] 输出&#xff1a;10 解释&#xff1a;最大的…