scrapy框架爬取网站
比如https://www.dushu.com/news/99.html 爬取这个分类下每篇文章的标题 作者 内容等
首先 创建工程
终端输入
scrapy startproject News
进入工程目录
cd News
创建 spider 文件 主要获取网页 及 处理在逻辑写在其中
scrapy genspider history www.dushu.com
这个读书网站是比较规则的 有 信息页 及详情页 可使用 CrawlSpider 爬取
先使用常规方法爬取
在history.py 中实现 页面获取解析逻辑
页面中自带一个类 继承 scrapy.Spider
类中有三个属性
name spider名。在执行爬虫文件时会用到
allowed_domains 允许的域名 www.dushu.com 可以删除
start_urls 默认识别解析的网页 换为https://www.dushu.com/news/99.html
scapy执行时 会调用 start_request()方法。。。默认是没有的。。。不是一定要重写该方法该方法会将根据网址生成 request请求。scrapy.Request(url)默认callback回调方法是parse 如果我们重写该方法要和默认执行一样 则为
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(url)
根据start_url中内容生成迭代器
parse函数负责解析 response网页
def parse(self,response)
# 获取下一页的链接
next_page_selector = response.xpath('//a[contains(text(),"下一页")]/@href')
if next_page_selector:
next_page_url = response.urljoin(next_page_selector.extract_first())
print(next_page_url)
# 生成请求 没有callback 默认为parse
yield scrapy.Request(next_page_url)
根据response我们可以获取下一页 。我们可以直接将下一页的链接使用scrapy.Request()包裹后 yield 这样根据新的url生成的request回调函数仍是parse。会继续执行直到下一页链接为空
这样我们就获得了横向的数据。即页面。而详情页的链接都包括在信息页中
接下来 获取详情页的信息。使用新的函数处理获取到的页面信息
news_url_seletors = response.xpath('//div[contains(@class,"news-item")]/p/a/@href').extract()
for news_url_end in news_url_seletors:
news_url = response.urljoin(news_url_end)
print(news_url)
yield scrapy.Request(news_url,callback=self.content_parse)
这仍然是parse函数的一部分
callback=self.content_parse content_parse是我们自己定义的处理详情页的函数
def content_parse(self,response):
title = response.xpath('//h1/text()').extract_first()
author = response.xpath('//div[@class="article-info"]/span/text()')[0].extract()
send_time = response.xpath('//div[@class="article-info"]/span/text()')[1].extract()
address = response.xpath('//div[@class="article-info"]/span/text()')[2].extract()
content = '\n'.join(response.xpath('//div[@class="text"]/p/text()').extract())
news_item = NewsItem()
news_item['title'] = title
news_item['author'] = author
news_item['send_time'] = send_time
news_item['address'] = address
news_item['content'] = content
yield news_item
可以看出我们yield了一个item
item是scrapy中的数据处理类型 在items.py中定义定义内容根据我们想要获取的信息设计。使用时导入Newsitem
class NewsItem(scrapy.Item):
title = scrapy.Field()
author = scrapy.Field()
send_time = scrapy.Field()
address = scrapy.Field()
content = scrapy.Field()
如果yield Request会根据回调函数处理获取到的response.而item则会经由中间键得到处理
处理item的逻辑在pipelines.py
class NewsPipeline(object):
def open_spider(self,spider):
print('开始处理数据')
# 建立连接
self.client = pymongo.MongoClient(host='10.31.153.34',port=27017)
# 建立或连接库
self.db = self.client['news']
# 建立表
self.collection = self.db['culture']
def process_item(self, item, spider):
self.collection.insert(dict(item))
self.collection.save()
return item
def close_spider(self,spider):
self.client.close()
print('处理完毕')
open_spider()和close_spider()会在爬虫开始执行与结束执行时调用。而process_item()每当有新的item时都会执行 此处简单起见保存到mongodb中。
为了能使pipelines.py中类能够执行。需要在setting中打开设置
ITEM_PIPELINES = {
# 'ReadNews.pipelines.ReadnewsPipeline': 300,
'ReadNews.pipelines.NewsPipeline': 300,
}
接下来只要终端执行。就可以看到效果
scrapy crawl history
这是常规使用方法。对于比较规则的数据。我们可以使用更方便的方法
# -*- coding: utf-8 -*-
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractor import LinkExtractor
from ..items import NewsItem
class NewsSpider(CrawlSpider):
name = 'news'
# allowed_domains = ['www.dushu.com']
start_urls = ['https://www.dushu.com/news/86.html']
rules = (
# 横向 查找 页 递归查找 没有指定 callback则默认 parse
# parse 不做解析因此不用写。只是获取页面 rules根据页面中有无符合Rule 继续查找
Rule(LinkExtractor(restrict_xpaths='//a[contains(text(),"下一页")]'),follow=True),
# 纵向 查找 详情页 详情页 不再继续作为 response 按照规则继续查找
Rule(LinkExtractor(restrict_xpaths='//div[contains(@class,"news-item")]/p/a'),callback='content_parse',follow=False),
)
def content_parse(self,response):
title = response.xpath('//h1/text()').extract_first()
author = response.xpath('//div[@class="article-info"]/span/text()')[0].extract()
send_time = response.xpath('//div[@class="article-info"]/span/text()')[1].extract()
address = response.xpath('//div[@class="article-info"]/span/text()')[2].extract()
content = '\n'.join(response.xpath('//div[@class="text"]/p/text()').extract())
news_item = NewsItem()
news_item['title'] = title
news_item['author'] = author
news_item['send_time'] = send_time
news_item['address'] = address
news_item['content'] = content
yield news_item
继承的类是CrawlSpider。在rules中定义的查找规则。
根据follow=True 则会根据获取到的response内容继续根据rules规则继续查找.False则不会进行对获取到的response继续查找
LinkExtractor可以获取标签所带链接
scrapy crawl news
可以获取同样的效果