scrapy 爬虫框架记要
scrapy 就是一个帮助爬取网站数据,帮助提取网站结构化数据的框架。
组件概览:
Scheduler :
Scrapy Engine: 引擎负责数据流在整个系统中的流动,也就是在你start 启动的那一瞬间,会有相应触发事件。
spiders: 爬虫程序, 里包括如何爬取网页,分析返回的response,提取item或者继续进入下一个URL,每一个spider都负责处理一个或者一些网站。
Downloader:负责获取页面数据并提供给引擎,然后提供给spider
∆∆Item Pipeline: 持久化(存取数据到数据库或者文件中), item Pipeline 负责处理被spiders爬取到的item(也就是html元素) ,将元素放入到这根管道中,管道中可以使用一些信号自定义一些操作。
Downloader Middlewares: 就是一个勾子,可以扩展scrapy功能。ø
Spider Middlewares: 也是一个勾子,可以扩展。
使用:
启动一个爬虫:
scrapy startproject projectName
cd projectName
scrapy gendspider baidu www.baidu.com #生成一个要爬取baidu网页的爬虫, 这里可以生成多个爬虫 。
scrapy crawl speedycloud --nolog. 启动爬虫,不显示日志
注解:
settings.py 文件 :
ROBOTSTXT_OBEY = False # Obey robots.txt rules #机器人协议,当蜘蛛在爬取一个网站时,首先会访问网站的robots.txt这个协议 # ,如同酒店里的"请匆打扰"挂牌,这个规则如同你尊重不尊重网站提供者的意愿
案例:
伯乐在线 的每篇文章点操作:
案例地址:git@github.com:tonywyl/jobbole_spider.git
# -*- coding: utf-8 -*- import scrapy import requests import re from scrapy.selector import Selector from scrapy.http import HtmlResponse,Request class XiaohuaSpider(scrapy.Spider): name = 'xiaohua' allowed_domains = ['jobbole.com'] start_urls = ['http://www.jobbole.com/'] cookie_dict={} def start_requests(self): for url in self.start_urls: yield Request(url,dont_filter=True,callback=self.parse0) def parse0(self,response): """ 登录 :param response: :return: """ login_url='http://www.jobbole.com/wp-admin/admin-ajax.php' post_data={ "action": "user_login", "user_login": 'beijinessa', "user_pass": 'seBBub%5w*Xa95gc', "remember_me": 1, "redirect_url": "http://www.jobbole.com", } import urllib.parse yield Request(url=login_url, method='POST', body=urllib.parse.urlencode(post_data), headers={'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}, callback=self.parse, ) print('登录操作:写入日志') def parse(self, response): print('login') """ 进入首页 :param response: :return: """ # print(response.text) # result=Selector(text=response.text).xpath('//h3/text()').extract()#不加extract 是保留HTML标签 # print(response.text,'----') yield Request(url='http://www.jobbole.com/',callback=self.parse00) """ android---- http://android.jobbole.com/wp-admin/admin-ajax.php top: http://top.jobbole.com/wp-admin/admin-ajax.php http://group.jobbole.com/wp-admin/admin-ajax.php 点赞 formdata { action:vote_post_action post_id:93250 } """ def parse00(self,response): """ 跳转至这一篇文章 :param response: :return: """ # print(response.text,'=-=-=-') url_list = response.selector.xpath('//div[@class="post-meta"]/p/a[@class="meta-title"]/@href').extract() # print(url_list) for url in url_list: yield Request(url=url, method='GET', callback=self.parse1) def parse1(self,response): last_url=re.findall('http://\w+\.\w+\.com',response.url)[0]#http://blog.jobbole.com/112239 last_url=last_url+'/wp-admin/admin-ajax.php' hxs=Selector(response) id=hxs.xpath('//div[@class="post-adds"]/span/@data-post-id').extract_first() # print(id,'=======') """cookie 获取""" from scrapy.http.cookies import CookieJar cookie_jar = CookieJar() cookie_jar.extract_cookies(response, response.request) for k, v in cookie_jar._cookies.items(): for i, j in v.items(): for m, n in j.items(): self.cookie_dict[m] = n.value data={ "action":"vote_post_action", "post_id":id, } # print(last_url) import urllib.parse # print(id, '---#--------') yield Request(url=last_url, method='POST', body=urllib.parse.urlencode(data), headers={"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"}, callback=self.parse2) def parse2(self,response): # print(response.text) from ..items import TutorialItem yield TutorialItem(text=response.text) #注册使用持久化。 # print(response.text,'---',) # print(response.encoding('utf-8'),'---',)
持久化:items.py #因为在parse2 函数注册了持久化,便会将text 进入pipeline
import scrapy class TutorialItem(scrapy.Item): # define the fields for your item here like: text = scrapy.Field() # pass
而pipeline 则可以做一些自己想要做的操作:如将item 写入日志
class TutorialPipeline(object): def __init__(self): self.f=None def process_item(self, item, spider):
#在spider/jobble.py的parse2 函数中,只要一yield就会触发process_item print('process item',item) self.f.write(item) return item @classmethod def from_crawler(cls, crawler): #只要爬虫一 start ,这个函数便会被触发,如果没有__init__的话。 print('pipline from process',) return cls() def open_spider(self,spider): #这是一个信号,当爬虫一打开就会触发这个,其余的还有close_spider self.f = open('log.log', 'ab+') print('spider start crawle write databases')