python 网站爬虫(四) Scrapy讲解
1、Spider类
Spider 类是 Scrapy 中的主要核心类,它定义了如何爬取某个(或某些)网站。包括爬取的动作(例如是否跟进链接),以及如何从网页的内容中提取结构化数据(爬取item)。spider类是scrapy框架最基础的类,以后配到的许多类,基本上都是继承自它。
Spider 是循环爬取,它的爬取步骤是:
start_requests 方法用 start_urls 中的 URL 初始化 Request ,然后将请求返回结果 Response 作为参数传递给 parse 方法;
parse 是回调函数,它分析传递过来的 Response 的内容,从中提取出 Item 对象、 dict 、 Request 或者包含三者的可迭代数据,将 Request 传递给 Scrapy 继续进行下一轮的循环;
parse 使用 selector 分析 Response 提取向所需的数据。
import scrapy
class DemoSpider(scrapy.Spider):
name = ‘demo’
allowed_domains = [‘https:www.baidu.com’]
start_urls = [‘http://https:www.baidu.com/’]
def parse(self, response):
pass
运行流程
模板中有一个start_urls参数,这是这个Spider的运行入口,Scrapy会自动的将这个参数中的url发送到Downloader进行下载,并且自动的调用parse方法来处理获得的response。
在parse方法处理response的过程中,我们一般会有可能获取两种对象,一个是最终我们从网页上提取的数据,这种数据我们会将其保存为item对象。另一种是我们获取的接下来要访问的url,这一种我们会将其生成为一个Request对象。这两种获得的对象,我们都会使用yield将其返回出去。Scrapy会自动检测对象的类型,如果是item,则会将其发送到item pipeline进行存储等处理,如果是Request对象,则会再次往Downloader发送进行访问。
每一个Request对象,都会在生成的时候绑定一个回调函数,用来处理这个请求返回的响应结果。
2、xpath
XPath,全称 XML Path Language,即 XML 路径语言。XPath 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历,它使用路径表达式来选取 XML 文档中的节点或节点集。XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointer 都构建于 XPath 表达之上。
Python 使用 XPath 要先安装 lxml 库
示例:
# python3
# -*- coding: utf-8 -*-
# Filename: xpath_demo.py
"""
练习使用 XPath 提取网页内容
@author: v1coder
"""
from lxml import etree
import requests
headers = {
'User-Agent': ''}
def get_content(url):
data = requests.get(url, headers=headers).content
return data
# 简书
def jianshu():
url = 'https://www.jianshu.com/p/713415f82576'
data = get_content(url)
html = etree.HTML(data)
# p[not(@class)] 为不含 class 属性的 p 节点
texts = html.xpath('//p[not(@class)]/text()')
for text in texts[:-1]:
print(text)
#jianshu()
# 代码解释:
# //p 为所有 p 元素
# //p[not(@class)] 为所有不含 class 属性的 p 元素
# /text() 为获取当前元素的文本
# 盗版小说网站
def biqukan_com():
url = 'https://www.biqukan.com/1_1094/5403177.html'
data = get_content(url)
html = etree.HTML(data)
texts = html.xpath('//div[@id="content"]//text()')
for text in texts:
print(text)
#biqukan_com()
# 代码解释:
# //div[@id="content"] 为获取包含 id 属性且属性值为 content 的所有 div 元素
# //text() 为获取当前节点及所有后代节点的文本
# 豆瓣电影 TOP250
def top_250():
url = 'https://movie.douban.com/top250'
data = get_content(url)
html = etree.HTML(data)
# 第一个 span 节点用 span[1]
texts = html.xpath('//div[@class="hd"]/a/span[1]/text()')
for text in texts:
print(text)
#top_250()
# 代码解释:
# /a 为当前节点的直接子节点中的 a 节点
# /span[1] 为直接子节点中的第一个 span 节点
# MZ图1
def mmjpg_com():
url = 'http://www.mmjpg.com/'
data = get_content(url)
html = etree.HTML(data)
# 获取属性 src 的值,用 attribute::src
urls = html.xpath('//img[@width="220"]/attribute::src')
for url in urls:
print(url)
#mmjpg_com()
# 代码解释:
# /attribute::src' 为获取当前元素的属性 src 的值
# MZ图2
def haopic():
url = 'http://www.haopic.me/tag/meizitu'
data = get_content(url)
html = etree.HTML(data)
urls = html.xpath('//div[@class="post"]/a/img/@src')
for url in urls:
print(url)
#haopic()
# 代码解释:
# //div 获取所有 div 元素
# '//div[@class="post"] 获取包含属性 class 且属性值为 post 的 div 元素
# /a 获取前面节点的直接子节点中的 a 节点
# /img 获取前面节点的直接子节点中的 img 节点
# /attribute::src 获取前面节点的属性 src 的值
# MZ图3
def mzitu():
url = 'https://www.mzitu.com/'
data = get_content(url)
html = etree.HTML(data)
urls = html.xpath('//img[@width="236"]/attribute::data-original')
for url in urls:
print(url)
#mzitu()
3、小例子
下面的代码用来抓取近期腾讯有关python的招聘信息,并将结果保存在job.json文件中。
import scrapy
import json
class Job1_Tenxun(scrapy.Spider):
name = 'job1'
start_urls = ['https://hr.tencent.com/position.php?keywords=python',]
def parse(self, response):
res = response.xpath("//tr[@class='even']|//tr[@class='odd']")
with open('job.json','a',encoding='utf-8') as f:
for tr in res:
item = {
'job_name':tr.xpath("./td[1]/a/text()").extract_first(),
'job_label':tr.xpath("./td[2]/text()").extract_first(),
'num':tr.xpath("./td[3]/text()").extract_first(),
'addr':tr.xpath("./td[4]/text()").extract_first(),
'time':tr.xpath("./td[5]/text()").extract_first(),
}
item = json.dumps(item,ensure_ascii=False)
f.write(item)
f.write('\n')
next_url = response.xpath("//a[@id='next']/@href").extract_first()
return scrapy.Request('https://hr.tencent.com/%s'%next_url)