爬虫scrapy-将某网站内的试题爬取出来并保存为本地markdown文件

这篇具有很好参考价值的文章主要介绍了爬虫scrapy-将某网站内的试题爬取出来并保存为本地markdown文件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前言

本文用于参考学习,请执行配置好scrapy环境后再进行编程实操
代码

pip install scrapy==2.5.1
pip install Twisted==22.10.0

单题效果:
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy


一、新建scrapy文件+配置setting

在配置好scrapy环境后在编译器终端参考如下图片中步骤建立一个scrapy文件。
注意:

  • scrapy startproject 文件夹的名字
  • scrapy genspider 爬虫文件名 爬取的网站域名(比如百度就是baidu.com)

怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
创建结果:
只需了解:
其中qpwj.py文件就是scrapy genspider 爬虫文件名 爬取的网站域名 —命令创建的,用来对网站的源代码进行解析(提取数据)
pipelines.py:数据管道,进行数据存储。
settings:配置scrapy文件,协调爬虫工作。
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
然后做这一步:
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy

本案例setting文件中做如下配置,个别对应值自己去浏览器中查:

USER_AGENT = "*****"   #浏览器中可查,按F12打开开发者模式点击network刷新网页点击网页文件找到USER_AGENT进行复制

ROBOTSTXT_OBEY = False #属于君子协议,改成False,就是爬,不管别人肯不肯
LOG_LEVEL = "WARNING" #少点无用的信息
DOWNLOAD_DELAY = 3 #这个一定要配好,控制延迟,不要太快,保护网站不崩
COOKIES_ENABLED = False #取消cook的自动维护
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
   "Cookie":"****" #自己给个cookie,登录网站就会得到
}
ITEM_PIPELINES = {
   #pipelines.py文件中的类的执行优先级,数字小的先执行
   'Problem.pipelines.ProblemPipeline': 300,
    'Problem.pipelines.PICPipeline':299
}
IMAGES_STORE ="./" # 给一个当前文件夹作为路径做参考来存储文件

两种方式新建执行srapy文件

  1. 新建一个runner.py(和scrapy.cfg同等级)文件:
#运行时右键run该文件就能执行Scrapy了
#tip:
#scrapy genspider 爬虫文件名 爬取的网站域名
from scrapy.cmdline import execute
if __name__ == '__main__':
    execute("scrapy crawl pqwj".split()) #注意pqwj替换为你的文件名

2.终端输入:

scrapy crawl pqwj

二、确定&分析需求

把这个网站所有的题目都爬下来,分类存放,文件格式(markdown),对于题目图片也存放一份在对应文件夹中。
确定文件分类形式:
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
直接举例:
一、资金时间价值的概念中的20道题目要都存放在一、资金时间价值的概念.md文件中,并且把图片都存放在同等级的img文件夹中
文件路径:
工程类/一级建造师/1Z101000工程经济/1Z101010资金时间价值的计算及应用/1Z101011利息的计算/一、资金时间价值的概念/一、资金时间价值的概念.md
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy

三、获取文件路径

发现first+second路径,而且有a标签,a标签中的href值是要用来进行拼接后来网页跳转的网址:
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
例如对含有一级建筑师文本的a标签进行href提取后进行网址拼接得到:

https://ks.wangxiao.cn/TestPaper/list?sign=jzs1

跳转到:
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
而我们的需求是跳转到:

https://ks.wangxiao.cn/exampoint/list?sign=jzs1

怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
两个网址一对比:

拿到的跳转网址:
https://ks.wangxiao.cn/TestPaper/list?sign=jzs1
目标:
https://ks.wangxiao.cn/exampoint/list?sign=jzs1

就差一个单词,观察其他网址是否也是如此,回答为:YES

那么:
进行一级目录和二级目录提取,并且向这些类目下的考点链接发送请求(拼接路径后进行替换单词)

        for i in all_li:
            onetitle = i.xpath(".//p/span//text()").extract_first()
            li_all_a=i.xpath(".//div[@class='send-title']/a")
            for j in li_all_a:
                twotitle  = j.xpath(".//text()").extract_first()
                twourl = resp.urljoin(j.xpath("./@href").extract_first()).replace("TestPaper","exampoint")
                yield scrapy.Request(
                    url=twourl,
                    callback=self.Plistparse,
                    meta={
                        "one":onetitle,
                        "two": twotitle
                    }
                )

观察题库&分析源码&拿下路径

访问题库后一点开,发现它的文件路径这样的:
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
题目路径有的深有的浅:

工程类\一级建造师\1Z101000工程经济\1Z101010资金时间价值的计算及应用\1Z101011利息的计算\一、资金时间价值的概念\一、资金时间价值的概念.md

工程类\一级建造师\1Z101000工程经济\现金流量图的计算\现金流量图的计算.md

这个怎么办?难道一套网页路径结构,就要写一套代码吗?

NO NO NO

可以先拿最里面的路径名:
比如:工程类\一级建造师\1Z101000工程经济\1Z101010资金时间价值的计算及应用\1Z101011利息的计算\一、资金时间价值的概念\一、资金时间价值的概念.md (.md这个文件名啊)
最里面的路径名:一、资金时间价值的概念
然后再从这个路径往外一层层的去拿路径名。

观察发现所有最里层的路径名都会放在类名为section-point-item的ul下第一个li中:
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
那我们就可以拿下所有的ul(section-point-item)让后进行遍历,一个个的去获取完整路径:
ul(section-point-item)的上层路径名都存放在ul[@class=‘section-item’ or @class=‘chapter-item’]ul类名为section-item或者chapter-item的标签中的第一个li中。

利用语句
i指的是ul(section-point-item)

i.xpath("./ancestor::ul[@class='section-item' or @class='chapter-item']")
会获得一个列表:
比如:一、资金时间价值的概念
会得到:
[1Z101000工程经济,1Z101010资金时间价值的计算及应用,1Z101011利息的计算]

对应得从外到里的关系:

怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy

all_sectionpointitem=resp.xpath(".//ul[@class='section-point-item']")
        onetitle=resp.meta["one"]
        twotitle=resp.meta["two"]
        if all_sectionpointitem:
            for i in all_sectionpointitem:
                thretitle= "".join(i.xpath("./li[1]//text()").extract()).strip().replace(" ","")
                #top sign的作用见下文
                top="".join(i.xpath("./li[2]//text()").extract()).strip().split("/")[1]
                sign="".join(i.xpath("./li[3]/span/@data_sign").extract()).strip().replace(" ","")
                subsign="".join(i.xpath("./li[3]/span/@data_subsign").extract()).strip().replace(" ","")
                r = [onetitle, twotitle]
                fj = i.xpath("./ancestor::ul[@class='section-item' or @class='chapter-item']")
                for j in fj:
                    p_name="".join(j.xpath("./li[1]//text()").extract()).strip().replace(" ","")
                    r.append(p_name)
                r.append(thretitle)
                dir_path="/".join(r)

跳转做题,拿下题目

怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
观察源码发现源码中两个网页没有可以发生跳转的链接,开始抓包:
在接收数据中发现POST请求:
题目数据存放在json中
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
观察多个网页的请求发现:

Payload中:
examPointType: ""  (不变)
practiceType: "2"  (不变)
questionType: ""    (不变)
sign: "jz1"           (变化)
subsign: "8cc80ffb9a4a5c114953" (变化)
top: "30"  (题目数量)

那top、sign、subsign在哪找呢?
观察
top:
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy
sign、subsign:
怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy

那么就有法发送请求获取题目数据了:

             data={
                    "examPointType": "",
                   "practiceType": "2",
                    "questionType": "",
                    "sign": sign,
                    "subsign": subsign,
                    "top": top
                }
                yield scrapy.Request(
                    url="https://ks.wangxiao.cn/practice/listQuestions",
                    method="POST",
                    body = json.dumps(data),
                    callback=self.parse_qu,
                    dont_filter=True,
                    headers={"Content-Type":"application/json; charset=UTF-8"},
                    meta={
                     "LJ":dir_path,
                     "filename":thretitle
                    }
                )

处理Json格式的题目数据

观察json文件格式发现在Data下存在多个字典每个字典下的questions(选择题)或者materials(材料题)键值内存放着题目信息。

#使用data.get("questions")  不存在"questions"键值就不会报错
#使用data["questions"]  不存在"questions"键值会报错
data.get("questions")

怎么把网站的题目导出来,Python--数据收集,爬虫,scrapy

 Datas = resp.json() #将json格式数据转为python对象
        datas = Datas["Data"]  #先从列表中拿下"Data"键下的题目数据
        for data in datas: #遍历datas列表,列表中存在一个个字典
            questions = data.get("questions") #获取"questions"键下的值,一个列表
            if questions:
                for q in questions: #遍历列表,进行题目数据提取
                    s=self.process_q(q)
                    #发送数据进行存储
                    yield {"path":resp.meta["LJ"],
                           "name":resp.meta["filename"],
                           "tm":s}
            else:
                materials = data.get("materials") #数据存放在"materials"列表中
                for mater in materials:
                    mater_content = mater["material"]['content']
                    questions = mater['questions']
                    qs = []
                    for q in questions:
                        q_info = self.process_q(q)
                        qs.append(q_info)
                    mater_content=mater_content+"\n\n"+qs
                    #发送数据进行存储
                    yield {"path":resp.meta["LJ"],
                           "name":resp.meta["filename"],
                           "tm":mater_content}

 def process_q(self,q):
        tm = q["content"] #题目内容
        op = q['options'] #题目选项
        jx = q['textAnalysis'] #题目解析
        op_list = []
        r_list = []
        for o in op:
            xxx = o["content"] 
            xx = o["name"] + "." + o["content"]
            op_list.append(xx)
            if o["isRight"] == 1:
                if o["name"] in "ABCDEFGHJK":
                    r_list.append(o["name"])
                else:
                    xxx = xxx + "\n"
                    r_list.append(xxx)
            else:
                pass
        s = tm + "\n" + "\n".join(op_list) + "\n" + "正确答案:" + "".join(r_list) + "\n" + jx+"\n" #组合题目内容,s就是一条完整的题目数据
        return s

s的内容示例(含图片的会有标签):

关于资金时间价值的说法,正确的是(   )。

A.资金周转速度的加快,对提升资金的时间价值有利 
B.资金的时间价值与资金的使用时间长短无关 
C.资金的时间价值与资金的数量无关 
D.资金总额一定,前期投入越多,资金的正效益越大 
正确答案:A
影响资金时间价值的因素很多,其中主要有以下几点:

1.资金的使用时间。在单位时间的资金增值率一定的条件下,资金使用时间越长,则资金的时间价值越大;使用时间越短,则资金的时间价值越小。B选项错误。

2.资金数量的多少。在其他条件不变的情况下,资金数量越多,资金的时间价值就越多;反之,资金的时间价值则越少。C选项错误。

3.资金投入和回收的特点。在总资金-定的情况下,前期投入的资金越多,资金的负效益越大;反之,后期投入的资金越多,资金的负效益越小。而在资金回收额一-定的情况下,离现在越近的时间回收的资金越多,资金的时间价值就越多;反之,离现在越远的时间回收的资金越多,资金的时间价值就越少。D选项错误。

4.资金周转的速度。资金周转越快,在一定的时间内等量资金的周转次数越多,资金的时间价值越多;反之,资金的时间价值越少。A选项正确。

【知识点】资金时间价值的概念

【考察方向】概念释义

【难易程度】易

存储数据

存数据时pipelines要导入的包:

import os
import scrapy
from lxml import etree
from scrapy.pipelines.images import ImagesPipeline

首先我们要考虑,材料题的数据中存在图片,我们得把图片下下来存放在对应文件夹里,并且对s中img标签进行src地址替换,让它根据本地文件路径显示图片。(注意是相对路径)

优先级较高的步骤,下载题目素材:

#ImagesPipeline ---继承ImagesPipeline中的方法get_media_requests、file_path、item_completed进行##方法重写
class PICPipeline(ImagesPipeline):
    #发送下载请求
    def get_media_requests(self, item, info):
        jxq=etree.HTML(item['tm']) #xpath定位
        srcs = jxq.xpath("//img/@src")
        for s in srcs:
            yield scrapy.Request(url=s,meta={"path":item['path'],"f_name":item['name'],"src":s},dont_filter=True)

    #确定文件保存位置和文件名字
    def file_path(self, request, response=None, info=None, *, item=None):
        path = request.meta['path']
        f_name = request.meta['f_name']
        wj_name = request.meta['src']
        real_name = wj_name.split("/")[-1]
        return path+"/"+"img"+"/"+real_name
     #下载结果处理---results
    def item_completed(self, results, item, info):
        #print(results)
        for i in results:
            status = i[0]  #下载状态-True --False
            dic = i[1]
            if status:
                src = dic['url']
                wzpath = dic['path'].split("/")[-2:]
                path = wzpath[0]+"/"+wzpath[1]
                item['tm'] = item['tm'].replace(src,path)
                print("替换为本地图片成功")
        return item  #一定return item将数据传递下去

优先级较低的步骤,把题目存下来:文章来源地址https://www.toymoban.com/news/detail-796090.html

    def process_item(self, item, spider):
        d_path = item['path']
        f_name = item['name']
        #如果文件路径不存在
        if not os.path.exists(d_path):
        #   创建它
            os.makedirs(d_path)
        #完整路径
        real_path = d_path+"/"+f_name+".md"
        f=open(real_path,mode="a",encoding="UTF-8")
        #写入题目
        f.write(item['tm'])
        f.write("\n\n")
        f.close()
        print("存下一道题目!")
        return item

到了这里,关于爬虫scrapy-将某网站内的试题爬取出来并保存为本地markdown文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python爬虫之Scrapy框架系列(21)——重写媒体管道类实现保存图片名字自定义及多页爬取

    spider文件中要拿到图片列表并yield item; item里需要定义特殊的字段名:image_urls=scrapy.Field(); settings里设置IMAGES_STORE存储路径,如果路径不存在,系统会帮助我们创建; 使用默认管道则在s

    2024年02月10日
    浏览(36)
  • 爬虫机试题-爬取新闻网站

    之前投简历时遇到了这样的一个笔试。本以为会是数据结构算法之类的没想到直接发了一个word直接提需求,感觉挺有意思就写了这篇文章,感兴趣的朋友可以看看。 通过分析页面结构我们得以知道,这个页面本身没有新闻信息,是由js代码执行后才将信息插入到html中的,因

    2024年04月25日
    浏览(28)
  • 利用scrapy框架对etherscan.io中给定Block范围内的交易信息的爬取

    一、 背景介绍 Etherscan 是 2015 年推出的一个以太坊区块探索和分析的分布式智能合同平台, 由于区块链中的交易信息等数据都是公开透明的 , 而 Etherscan 作为探索以太坊的窗口, 用户可以使用其查看自己的交易详情以及以太坊中的任何信息。 我们都有过这样的经历, 打开 taoba

    2024年02月12日
    浏览(35)
  • 爬虫:Scrapy热门爬虫框架介绍

    结合自身经验和内部资料总结的Python教程,每天3-5章,最短1个月就能全方位的完成Python的学习并进行实战开发,学完了定能成为大佬!加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础)》 再推荐一下最近热更的:《大厂测试高频面试题详解》 该专栏对近年

    2024年02月13日
    浏览(31)
  • 爬虫---scrapy爬虫框架(详细+实战)

    ​ 活动地址:CSDN21天学习挑战赛 1、基本功能 Scrapy 是一个适用爬取网站数据、提取结构性数据的应用程序框架,它可以应用在广泛领域:Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。通常我们可以很简单的通过 Scrapy 框架实现一个爬虫,抓取指

    2023年04月22日
    浏览(38)
  • 爬虫(四):Scrapy热门爬虫框架介绍

    结合自身经验和内部资料总结的Python教程,每天3-5章,最短1个月就能全方位的完成Python的学习并进行实战开发,学完了定能成为大佬!加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础)》 再推荐一下最近热更的:《大厂测试高频面试题详解》 该专栏对近年

    2024年02月11日
    浏览(32)
  • 【网络安全带你练爬虫-100练】第14练:文件内容的读取、取出

    目录 一、目标1:把文件内容遍历取出 二、目标2:把文件内容全部取出 三、网络安全O  (1)如果文件脚本在不同目录 (2)如果文件直接和脚本在同一目录  (1)存放取出的元素 (2)将目标文件内容的元素依次取出 (for循环) (3)所有元素依次添加进列表中 (4)完整

    2024年02月16日
    浏览(26)
  • Scrapy-爬虫模板的使用

    Scrapy,Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。 Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改。它也提供了多种类型爬虫的基类

    2023年04月09日
    浏览(20)
  • Python 爬虫—scrapy

    scrapy用于从网站中提取所需数据的开源协作框架。以一种快速、简单但可扩展的方式。 该爬虫框架适合于那种静态页面, js 加载的话,如果你无法模拟它的 API 请求,可能就需要使用 selenium 这种使用无头浏览器的方式来完成你的需求了 运行 代码中通过 main 方式运行调试 简

    2024年02月10日
    浏览(30)
  • scrapy ---分布式爬虫

     原来scrapy的Scheduler维护的是本机的任务队列(待爬取的地址)+本机的去重队列(放在集合中)---》在本机内存中 如果把scrapy项目,部署到多台机器上,多台机器爬取的内容是重复的  所以实现分布式爬取的关键就是,找一台专门的主机上运行一个共享的队列比如Redis, 然后

    2024年02月16日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包