一、前言
上一篇给大家仔细讲解了如何用Xpath分类爬取医疗信息网站医疗器材名称和介绍图片,以及三种最常用的存储方法。
本篇是本系列的第八篇了,今天给大家讲讲如何用Scrapy系统爬取伯乐在线文章信息。
二、你不得不知道的 Knowledge
1.CSS选择器获取标签内容值和标签属性值
代码语言:javascript复制eg. <a href = "https://blog.csdn.net/qq_39241986">极简XksA的博客</a>
# 1.获取标签里的内容值
response.css("a::text").extract()
极简XksA的博客
# 2.获取href属性值
response.css("a::attr(href)")
https://blog.csdn.net/qq_39241986
2.urllib包下的parse函数作用
代码语言:javascript复制# python3下
from urllib import parse
url_main = "https://blog.csdn.net"
post_url = "/qq_39241986"
'''
urljoin函数参数介绍:
url_main :第一个参数为主域名;
post_url :第二个参数为需补全部分;
'''
url= parse.urljoin(url_main,post_url)
print(url)
# result :
# https://blog.csdn.net/qq_39241986
通过代码容易看出,urllib包下的parse函数作用是能够补全我们获取的不完全链接(在上一篇中我们获取到的商品类别url就是不完全的url,当时是我们自己写方法修正的数据)
3.yield关键字介绍
一个带有 yield 的函数就是一个 generator(生成器),它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。
三、看代码,边学边敲边记Scrapy爬取伯乐在线
1.爬取逻辑思路分析
爬取逻辑思路
图上已经绘画和写的比较清楚了,一个简单思路就是:请求页面 -> 获取文章和下页链接 -> 获取文章详细信息 -> 翻页,再从头开始,一直到爬完所有页面,所有文章,下面我们具体动手试试。
2.调试方便,我们还是在cmd下用scrapy shell 进行调试
(1)获取主页面所有文章的url
1)页面分析:
页面分析文章url获取方法
通过图片上面标记,容易看出,我们要获取的文章url在 id 为archive
的div下的class为post floated-thumb
的div下的class为post-thumb
的div下的a标签的href
属性中,哈哈,读起来有点拗口,这里提供两种方法获取相应内容:
Xpath路径:
代码语言:javascript复制'//*[@id="archive"]/div/div[1]/a/@href'
CSS选择器:
代码语言:javascript复制# 注:因为post floated-thumb这个类名中 post和floated-thumb中间有个空格,表示两个类名,
# 我们可以直接根据后面部分来查找到这个class。(attr用来取属性值)
"#archive .floated-thumb .post-thumb a::attr(href)"
2)shell下运行结果
代码语言:javascript复制# 我选择的是Xpath获取,个人比较习惯
>>> response.xpath('//*[@id="archive"]/div/div[1]/a/@href').extract()
['http://blog.jobbole.com/114334/', 'http://blog.jobbole.com/114331/', 'http://blog.jobbole.com/114329/', 'http://blog.jobbole.com/114327/', 'http://blog.jobbole.com/114324/', 'http://blog.jobbole.com/114321/', 'http://blog.jobbole.com/114319/', 'http://blog.jobbole.com/114311/', 'http://blog.jobbole.com/114308/', 'http://blog.jobbole.com/114303/',
'http://blog.jobbole.com/114297/', 'http://blog.jobbole.com/114285/', 'http://blog.jobbole.com/114283/', 'http://blog.jobbole.com/114280/', 'http://blog.jobbole.com/114276/', 'http://blog.jobbole.com/114273/', 'http://blog.jobbole.com/114270/', 'http://blog.jobbole.com/114268/', 'http://blog.jobbole.com/114261/', 'http://blog.jobbole.com/114168/']
(2)获取翻页链接
1)页面分析:
页面分析获取翻页链接url
通过图片上面标记,容易看出,我们要获取的翻页url在class为next page-numbers
的a标签的href
属性中,中这里提供两种方法获取相应内容:
Xpath路径:
'//*[@id="archive"]/div[21]/a[4]/@href'
CSS选择器:
代码语言:javascript复制# 页面上查找发现,next 属性值是唯一的,
# 所以可以直接根据类名next来查找下一页的url。
".next::attr(href)"
2)shell下运行结果
代码语言:javascript复制# 我选择的是CSS选择器获取,一眼看出比较简单嘛
>>> response.css(".next::attr(href)").extract()[]
'http://blog.jobbole.com/all-posts/page/2/'
3.在Pycharm下实操代码
(1)基础代码
代码语言:javascript复制# -*- coding: utf-8 -*-
import scrapy
import re
# 发送请求爬取页面
from scrapy.http import Request
# 归正url
from urllib import parse
# 爬虫类
class JobboleSpider(scrapy.Spider):
name = 'jobbole'
allowed_domains = ['blog.jobbole.com']
start_urls = ['http://blog.jobbole.com/all-posts/']
(2)获取文章url下载和翻页下载代码
代码语言:javascript复制# 爬取页面所有文章url和翻页url
# 翻页下载
def parse(self, response):
# 1.获取单页面文章url
post_urls = response.xpath('//*[@id="archive"]/div/div[1]/a/@href').extract()
# 2.下载文章url
for post_url in post_urls:
yield Request(url= parse.urljoin(response.url,post_url),callback= self.parse_detail)
# 3.获取翻页url和翻页下载
next_url = response.css(".next::attr(href)").extract()
if next_url != []:
next_url = next_url[]
yield Request(url= parse.urljoin(response.url,next_url),callback= self.parse)
(3)解析单篇文章信息
代码语言:javascript复制# 获取单篇文章详情信息
def parse_detail(self,response):
# 文章标题
title = response.css(".entry-header h1 ::text").extract()[]
# 发布日期
data_r = response.css(".entry-meta-hide-on-mobile::text").extract()[].strip()
data_time = data_r.replace('·','').strip()
# 文章分类
article_type = response.css("p.entry-meta-hide-on-mobile a::text").extract()
if article_type != []:
article_type = ",".join(article_type)
# 点赞数
praise_number = response.css(".href-style.vote-post-up h10::text").extract()
if praise_number != [] :
praise_number = int(praise_number[])
else:
praise_number =
# 收藏数
collection_str = response.css("span.btn-bluet-bigger:nth-child(2)::text").extract()[]
reg_02 = '.*?(d ).*'
collection_number = re.findall(reg_02, collection_str)
if collection_number:
collection_number = int(collection_number[])
else:
collection_number =
# 评论数
comment_number = response.css("a[href='#article-comment'] span::text").extract()[]
comment_number = re.findall(reg_02, comment_number)
if comment_number:
comment_number = int(comment_number[])
else:
comment_number =
print("文章标题:" title)
print("发布日期:" data_time)
print("文章分类:" article_type)
print("点赞数:" str(praise_number))
print("收藏数:" str(collection_number))
print("评论数:" str(comment_number))
print("----------------------------------------")
(4)整合上面(1)、(2)、(3)后在pycharm下运行效果
我运行了差不多7-9秒,目测爬取了100条信息应该有,所以在爬取速度和可靠性上,依靠框架爬取要比自己request好的多嘿。
运行部分截图
代码语言:javascript复制文章标题:泪流满面的 个 Git 面试题
发布日期://
文章分类:IT技术,Git
点赞数:
收藏数:
评论数:
----------------------------------------
文章标题:设计微服务的最佳实践
发布日期://
文章分类:IT技术,微服务
点赞数:
收藏数:
评论数:
----------------------------------------
···
文章标题:如何自动唤醒和关闭 Linux
发布日期://
文章分类:IT技术,Linux
点赞数:
收藏数:
评论数:
----------------------------------------
文章标题:他们是优秀的前端,所以这些后端工作也交给他们…
发布日期://
文章分类:职场,程序员
点赞数:
收藏数:
评论数:
----------------------------------------
四、后言
通过本次学习,不知道大家有没有对Scrapy有多一点点了解嘿,通过本次学习我知道了如何把页面发送给Scrapy,让它帮忙下载,即使是几千条数据,也没有出现连接错误,同时知道了关键字yield
的基本使用方法,我觉得最重要的是我们爬取的思路,以及在爬取过程中如何选取更加适合的匹配方法(目前我们已经讲了:正则、Xpath、CSS选择器)。
继续加油,下一节我们将讲解如何设计数据库来存储我们获取的数据,并利用items
方法交给pipelines
进行数据存储和查重。
【完】