k、scrapy之综合应用
scrapy之综合应用
1、LinkExtractors
LinkExtractors:链接提取器,只负责提取链接,即a标签的内容
1.1、导入
from scrapy.linkextractors import LinkExtractor
1.2、scrapy shell 使用
例:scrapy shell https://www.dytt8.net/html/gndy/dyzz/index.html
-
创建对象
- extractor = LinkExtractor(提取规则) #提取规则 是针对标签,提取所有link(a的href)添加到调度器Scheduler
-
提取规则
-
直接使用正则表达式
extractor = LinkExtractor('list_23_\d+?\.html')
-
allow:提取符合正则的链接
-
deny:不提取符合正则的链接
-
restrict_xpaths
-
xpath,提取符合xpath规则的链接
注意:不需要写a标签,只需要提取到a标签外层即可,会自动把a标签内的链接提取出来
-
eg:
>>> extractor = LinkExtractor(restrict_xpaths='//div[@class="x"]') >>> alinks = extractor.extract_links(response) >>> alinks extracts_links(resp) -> list[Link, Link, ...., Link] Link url 提取的<a>标签中的href text 提取的<a>标签中的文本
-
-
restrict_css:提取符合选择器规则的链接,不需要加a标签
eg:
>>> extractor = LinkExtractor(restrict_css='.x') >>> alinks = extractor.extract_links(response) >>> alinks >>> alinks[0].url, alinks[0].text
-
-
提取链接
#获取连接的路径和文本名称
links = extractor.extract_links(response)
for link in links:
print(link.url, link.text)
1.3、创建爬虫文件
需要使用crawlspider,CrawlSpider是一个类,它的父类就是scrapy.Spider,所以CrawlSpider不仅有Spider的功能,还有自己独有的功能。CrawlSpider可以定义规则,再解析html内容的时候,可以根据链接规则提取出指定的链接,然后再向这些链接发送请求,所以,如果有需要跟进链接的需求,就可以使用CrawlSpider来实现
scrapy genspider -t crawl 爬虫名 域名
使用模板 crawlspider 创建爬虫类
1.4、读书网
# -*- coding: utf-8 -*-
import scrapy
# 链接提取器
from scrapy.linkextractors import LinkExtractor
# CrawSpider导入
from scrapy.spiders import CrawlSpider, Rule
class ReadSpider(CrawlSpider):
name = 'read'
allowed_domains = ['www.dushu.com']
start_urls = ['https://www.dushu.com/book/1081.html']
# 建议不要重写父类的pares方法,框架负责实现
# # 父类的逻辑
# def parse(self, response):
# pass
# 指定了页面内链接的提取规则,会被父类自动调用
# callback必须使用字符串传递函数名称
# follow是否跟进链接(继续提取链接中的链接)
# LinkExtractor对象的提取规则需要我们制定
rules = (Rule(LinkExtractor(allow=r'/book/1081_\d+?.html'), callback='parse_item', follow=False),)
# 可以自定义,只要保证callback的参数与这个函数名一致即可
# parese_item方法会把所有提取到的请求对象的返回值接收到
# 如果提取到的链接有重复的,会自动过滤
def parse_item(self, response):
book_list = response.xpath('//div[@class="bookslist"]/ul/li')
for book in book_list:
item = {}
#标题
item['title'] = book.xpath('./div[@class="bookinfo"]/h3/a/@title').extract_first()
#作者
item['author'] = book.xpath('./div[@class="book-info"]/p/a/text()').extract_first()
#图片
item['img_url'] = book.xpath('./div[@class="book-info"]/div/a/img/@data-original').extract_first()
yield item
2、日志LOG
-
级别
-
CRITICAL:严重错误
-
ERROR:一般错误
-
WARNNING:警告信息
-
INFO:一般信息
-
DEBUG:调试信息
默认级别为DEBUG,只要出现DEBUG及以上的错误级别,都会打印
-
-
设置级别
设置的日志级别会过滤掉低于当前定制级别的日志信息
例如设置日志级别为warnning则过滤掉Info和debug
-
settings文件中添加
参考: https://docs.scrapy.org/en/latest/topics/logging.html
LOG_LEVEL = '日志等级' LOG_FILE= 'name.log'
-
-
扩展
-
logging的日志模块
-
spider.logger.info('Spider opened: %s' , spider.name):scrapy中日志记录器的名称是爬虫的名字
-
sys.execepthook
-
如果python程序中发生了某些异常,且没有try-except处理时,则会由解释器处理
-
解释器会调用sys.excepthook函数处理,全局异常处理
-
如果我们指定excepthook执行的函数 ,
但是指定的全局异常处理函数必须有3个参数-
except_type:异常类
-
except_value:异常的信息
-
traceback:异常跟踪栈的对象
-
tb_frame:异常栈的信息
- f_code
- f_lineno
- f_locals
-
tb_next:下一个trackback对象
-
tb_lineno:跟踪的行号
-
tb_lasti
-
-
eg:
import sys def download(url): print('开始下载', url) # 程序在运行的过程中可能会出现的异常 # 针对此异常,我们的程序并没有处理 raise Exception('--下载超时-') def global_except(except_type, msg, trackback): print('-------上报程序中断/异常信息------') print(except_type, msg) print(dir(trackback)) # 显示当前异常帧frame print(trackback.tb_frame.f_lineno,trackback.tb_frame.f_code.co_name, trackback.tb_frame.f_locals) # 显示下一个常帧的跟踪位置信息 print(trackback.tb_next.tb_frame.f_lineno,trackback.tb_frame.f_code.co_name, trackback.tb_next.tb_frame.f_locals) print(trackback.tb_next.tb_next) print('-----------------------') if __name__ == '__main__': sys.excepthook = global_except download('http://www.baidu.com/s?kw=123')
-
-
3、处理POST请求
-
Request
-
url
-
callback
-
meta:元数据,指定一个字典做为参数,用于spider和引擎之间传参
-
headers
-
cookies
-
priority
-
dont_filter
-
-
Response
-
text:文本数据
-
encoding:文本的编码
-
body:字节码数据
-
meta:元数据
-
status
-
url
-
headers
-
request
-
-
start_requests(self)
#定制此方法,这个方法是一个重写方法,不要修改名字和参数 # -*- coding: utf-8 -*- import scrapy import json class FanyiSpider(scrapy.Spider): name = 'fanyi' allowed_domains = ['fanyi.baidu.com'] # 重写方法,不是自定义方法,由引擎自动调用 def start_requests(self): post_url = 'http://fanyi.baidu.com/sug' data = { 'kw': 'baby' } # 提交post请求 # url post地址 # formdata post参数 # headers post请求头 # callback 回调函数,引擎会把response对象回传给这个指定的函数 yield scrapy.FormRequest(url=post_url,formdata=data,callback=self.parse_info) # 自定义的函数,由callback指定的回调方法 def parse_info(self, response): obj = json.loads(response.text,encoding='utf-8') string = json.dumps(obj,ensure_ascii=False) # 解析内容即可 print(string)
-
删除spider文件中的start_Urls属性和parse函数
-
yield scrapy.FormReuqest():需要在start_request函数内使用此方法返回一个POST请求对象
-
url:POST请求的地址
-
formdata:POST要携带的表单数据
data = { key:value }
-
headers:定制请求头信息
-
cookies
-
callback:处理解析逻辑的回调函数,需自己定义
-
-
yield scrapy.Reqeust():提交GET 请求使用的方法
-
yield:方法调用前一般加yield表示返回这个对象给引擎
-
4、设置代理
-
settings文件设置
- 开启DOWNLOADER_MIDDLEWARES
-
middlewares文件修改
- 实现下载中间件指定的类中的process_request方法
- 添加代码:request.meta['proxy'] = 'http://101.236.60.8:8866'
5、处理登陆
-
cookies设置
- 需要使用cookie可以设置COOKIES_ENABLED为True
- 执行步骤同POST请求
6、写入MySql
-
settings中添加新的管道
ITEM_PIPELINES = { 'dushuproject.pipelines.DushuprojectPipeline': 300, 'dushuproject.pipelines.MysqlPipeline': 299, }
-
settings中添加数据库配置信息
DB_HOST = '127.0.0.1' DB_PORT = 3306 DB_USER = 'root' DB_PWD = '123456' DB_NAME = 'test' DB_CHARSET = 'utf8'
-
pipelines文件修改
from scrapy.utils.project import get_project_settings import pymysql # 添加如下新的管道,用于数据库文件操作 class MysqlPipeline(object): """docstring for MysqlPipeline""" def __init__(self): settings = get_project_settings() self.host = settings['DB_HOST'] self.port = settings['DB_PORT'] self.user = settings['DB_USER'] self.pwd = settings['DB_PWD'] self.name = settings['DB_NAME'] self.charset = settings['DB_CHARSET'] self.connect() def connect(self): self.conn = pymysql.connect(host=self.host,port=self.port,user=self.user, password=self.pwd,db=self.name,charset=self.charset) self.cursor = self.conn.cursor() def close_spider(self, spider): self.conn.close() self.cursor.close() def process_item(self, item, spider): sql = 'insert into book(image_url, book_name, author, info) values("%s", "%s", "%s", "%s")' % (item['image_url'], item['book_name'], item['author'], item['info']) # 执行sql语句 self.cursor.execute(sql) return item
-
数据库引擎
- MyISAM
- pymysql