失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Python 网络爬虫:Scrapy框架下爬虫的简单思路

Python 网络爬虫:Scrapy框架下爬虫的简单思路

时间:2022-07-29 04:21:50

相关推荐

Python 网络爬虫:Scrapy框架下爬虫的简单思路

文章目录


文章目录

文章目录前言一、分析数据源思路分析二、代码部分总结

前言

最近写了一个词典网站的爬虫,响应以及获取数据的方式非常的简单,本以为会是个轻松的爬虫脚本,没曾想出了很多意料之外的问题,这样使得我对代码本身有了更加清晰的认知。


提示:以下是本篇文章正文内容,下面案例可供参考

一、分析数据源

在爬取所需的资源时,首当其冲的就是要确认数据来源,数据具体在什么位置,数据的目录页,分类所进入的逻辑是什么等等。笔者在编写一个爬虫脚本之前往往会先思考这个问题,只要将逻辑考虑的清晰顺畅,后面我们所做的代码编写会轻松很多。

目标网站:/zhs

思路分析

首先进入主页,引入眼帘的是如下页面:

左侧是网站的目录,我们的目的是拿到该词典的古文双译句子。按照该网站的目录情况,似乎该词典网站的数据大体上分为"先秦两汉"和"汉代之后"两类,我们尝试点进去看看。

注意这里url的变化,在进入"先秦两汉"页面后,首先网站的url发生了变化,多了一个/pre-qin-and-han/部分,这次可以初步判定这是一个get请求。并且在切换英文繁体的时候,仅是ulr的后缀发生了变化,而且我们发现在英文和繁体的页面中,会直接带每一句其相应的英文翻译,这样的话,我们最终的目标页就确定了,我们只需要进入该页面就可以拿到我们所需的内容。

再其次我们发现,在"先秦两汉"的页面中,似乎其下的分类,例如:论语,孟子等等都是以及加载好了,似乎我们并不需要经过"论语"这一部分。我们在"先秦两汉"的页面中就可以拿到每一部古文经典中每一篇的url。我们打开F12调试验证一下:

果然,验证了之前我们的猜想,可是这里似乎还多了例如:儒家,墨家,道家等这样“先秦两汉”次级目录下的url,并且在这里的页面规则下,我们利用xpath提取相应的href时会包含它们。我们初步的思路是跳过这一次级目录,直接取"儒家,墨家,道家等"其下的每一篇的url,那会不会有影响呢?我们分别点进两种页面看看。

答案是不会,即使我们将"先秦两汉"页面中的包含了"论语,孟子"等url提取并访问,但在我们进去真正所需页面,例如"儒家"的次级目录中的"论语"时,编写的xpath才能提取到真正所需的内容,而其他页面获取为空。

截止目前,我们的思路是:先进入"先秦两汉"的页面,再访问"先秦两汉"目录下的所有url,随后在进入到例如:“论语”,"孟子"页面中的每一篇文章的url,这样即可拿到目标资源。

用个实例来理一理:

/pre-qin-and-han/ens → /analects/ens → /analects/xue-er/ens

大致上是这样的顺序。

在访问页面的时候,我发现似乎并不是每一篇文章都有英文翻译,并且我还发现个别文章比我们预想的访问顺序会少一级,如图:

我们访问"独断"时,按照顺序显示的页面应该是"独断"目录下的每一篇文章的url,但这这里却直接显示出了目标内容,如图:

这是一个小坑,如果忽略这一点可能会导致我们爬取的数据不全,产生遗漏。所幸通过观察,我发现,带有中英文翻译的页面,在我们访问的第二级,也就是例如:"论语"的页面,"论语"页面中是其下每一篇文章的url,如果该篇文章内含中英文翻译,那该篇文章的url的标题结构就是 中文 + “-” + “英文”,而不带有英文翻译的 标题结构仅是 中文。如图:

似乎逻辑思路已经完善了,但在我编写代码完后发现中英文的数量对不上,中文会比英文的数量要多,这让我非常难受,在仔细排查一番后我发现,问题是出在最后的目标页面上,如图:

我们发现,如图上这个作为例子,安装思路,我们先进入 /pre-qin-and-han/ens,然后进入 /mozi/ens,而在墨子的页面中,其图示路径也不同,如图:

若是点箭头所指的url,一般是如图下所示的页面:

但"墨子"的"卷十一"却不同,如图:

"卷十一"的内容不是次级url而是目标文本,并且其文本中英文并不是一一对应。这个网站的页面属实有点乱,不过好在确定了思路,下面是代码部分。

二、代码部分

代码如下(示例):

import scrapyfrom redis import Redisfrom lxml.html import etreefrom html import unescapefrom scrapy import cmdline, selector, Requestclass ClassicalSpider(scrapy.Spider):name = 'classical'start_urls = ['/pre-qin-and-han/ens','/post-han/ens']conn = Redis(host='127.0.0.1', encoding='utf-8', port=6379)def parse(self, response):url_primary = response.xpath('//*[@id="content3"]/a/@href').getall()for i in url_primary:yield response.follow(url=i, callback=self.parse_detail,dont_filter=True)def parse_detail(self, response):b = response.bodypage = etree.HTML(b)page = unescape(page)whole_url = []whole_title = []Available_url = []Available_title = []content_chs_list = []content_ens_list = []for bad in page.xpath('//*[@id="content3"]/table[@border="0"]//td[@class="etext"]/p'):bad.getparent().remove(bad)for y in page.xpath('//table[@border="0"]'):content_chs = [x.xpath('string(.)').strip() for x in y.xpath('.//td[@class="ctext"]') ifx.xpath('string(.)').strip()]content_ens = [x.xpath('string(.)').strip() for x in y.xpath('.//td[@class="etext"]') ifx.xpath('string(.)').strip()]if len(content_chs) == len(content_ens):for i in content_chs:content_chs_list.append(i.strip())for i in content_ens:content_ens_list.append(i.strip())content_secondary = response.xpath('//*[@id="content2"]/a/@href').extract()for i in content_secondary:whole_url.append(i)title_primary = response.xpath('//*[@id="content2"]/a/text()').getall()for i in title_primary:whole_title.append(i)for whole_title,whole_url in zip(whole_title,whole_url):if whole_title.find('-')>=0:Available_url.append(whole_url)Available_title.append(whole_title)for ture_url in Available_url:yield response.follow(url=ture_url, callback=self.parse_page,meta={'chs': content_chs_list,'ens':content_ens_list})def parse_page(self, response):content = response.bodypage = etree.HTML(content)page = unescape(page)content_chs_list = response.meta['chs']content_ens_list = response.meta['ens']for bad in page.xpath('//*[@id="content3"]/table[@border="0"]//td[@class="etext"]/p'):bad.getparent().remove(bad)for y in page.xpath('//table[@border="0"]'):content_chs = [x.xpath('string(.)').strip() for x in y.xpath('.//td[@class="ctext"]') ifx.xpath('string(.)').strip()]content_ens = [x.xpath('string(.)').strip() for x in y.xpath('.//td[@class="etext"]') ifx.xpath('string(.)').strip()]if len(content_chs) == len(content_ens):for i in content_chs:content_chs_list.append(i.strip())for i in content_ens:content_ens_list.append(i.strip())if len(content_chs_list)==len(content_ens_list):ch_url = (response.url).replace('/ens','')yield response.follow(url=ch_url, callback=self.parse_ch,meta={'chs': content_chs_list,'ens':content_ens_list})def parse_ch(self, response):item = {}content_chs_list = response.meta['chs']content_ens_list = response.meta['ens']content = response.bodypage = etree.HTML(content)page = unescape(page)content_ch_list = []for bad in page.xpath('//*[@id="content3"]/table[@border="0"]//td[@class="etext"]/p'):bad.getparent().remove(bad)for y in page.xpath('//table[@border="0"]'):content_ch = [x.xpath('string(.)').strip() for x in y.xpath('.//td[@class="ctext"]') ifx.xpath('string(.)').strip()]content_ens = [x.xpath('string(.)').strip() for x in y.xpath('.//td[@class="etext"]') ifx.xpath('string(.)').strip()]if len(content_ch) == len(content_ens):for i in content_ch:content_ch_list.append(i.strip())# content_ch = [x.xpath('string(.)') for x in page.xpath('//*[@id="content3"]/table[@border="0"]//td[@class="ctext"]')]# for i in content_ch:#if i.strip():# content_ch_list.append(i.strip())if len(content_chs_list) == len(content_ens_list) == len(content_ch_list):for chs,ch,ens in zip(content_chs_list,content_ch_list,content_ens_list):item['chs'] = chsitem['ch'] = chitem['ens'] = ens# print(item)yield itemif __name__ == '__main__':cmdline.execute(["scrapy", "crawl", "classical"])

总结

在完成一个网站代码的编写的同时,多关注逻辑部分以及代码本身,即使是简单的网站,不同代码的执行效率等也是不同的,这正是我们需要学习进步的点。

如果觉得《Python 网络爬虫:Scrapy框架下爬虫的简单思路》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。