目录
一、Scrapy流程
二、创建工程
scrapy startproject telnote
生成工程之后的目录结构:
三、创建Spider
scrapy genspider TNSpider telnote.cn
生成Spider之后的目录结构
生成的Spider代码:
# -*- coding: utf-8 -*-
import scrapy
class TnspiderSpider(scrapy.Spider):
name = 'TNSpider'
allowed_domains = ['telnote.cn']
start_urls = ['http://telnote.cn/']
def parse(self, response):
pass
四、编写逻辑代码
# -*- coding: utf-8 -*-
import scrapy
class TnspiderSpider(scrapy.Spider):
name = 'TNSpider'
allowed_domains = ['telnote.cn']
start_urls = ['https://www.telnote.cn/xiaohua/jiating/']
def parse(self, response):
for item in response.css('div.W_linka'):
yield {
'连接': response.urljoin(item.css('h1 > a').attrib['href']),
'内容': item.css('dl.comment::text').extract_first(),
}
next_page = response.urljoin(response.css('div.pages ul li a::attr("href")')[-2].extract())
done = "list_3.htm" in next_page
if next_page is not None and not done:
yield scrapy.Request(next_page, self.parse)
五、执行
5.1 命令方式
scrapy crawl TNSpider -o data.json
scrapy默认是把parse输出到日志文件中的,可以通过启动的命令惨-o指定把数据输出到指定的文件。
需要在项目目录下执行命令,如果是在不知道怎么区分,就找scrapy.cfg文件,scrapy.cfg文件同级的目录下执行就可以。
5.2 代码方式
from scrapy.cmdline import execute
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
execute(["scrapy", "crawl", "TNContent"])
execute方法的参数就是对使用命令调用方式封装成了列表。
代码方式的好处就是我们可以在IDE中进行调试。
六、配置输出
FEED_EXPORT_ENCODING = 'utf-8'
默认输出的是Unicode,这里配置输出编码为utf-8
七、使用CrawlSpider
7.1 使用命令生成CrawlSpider
scrapy genspider -t crawl TNContent telnote.cn
7.2 Item
# -*- coding: utf-8 -*-
import scrapy
class TelnoteItem(scrapy.Item):
title = scrapy.Field()
content = scrapy.Field()
pub_time = scrapy.Field()
7.3 CrawlSpider逻辑
CrawlSpider和Spider不同的是CrawlSpider会把页面中解析出来的url添加添加到请求队列中去,这就更像一个爬虫了。
我们可以利用CrawlSpider来简化我们抓取整个网站。
CrawlSpider中一个重要的属性就是rules,可以定义要抓取哪些url。
# -*- coding: utf-8 -*-
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class TncontentSpider(CrawlSpider):
name = 'TNContent'
allowed_domains = ['telnote.cn']
start_urls = ['https://www.telnote.cn/xiaohua/jiating/']
rules = (
# https://www.telnote.cn/xiaohua/48/47459.htm 内容页面
Rule(LinkExtractor(allow=r'https://www.telnote.cn/xiaohua/\d+/\d+.htm'), callback='parse_item', follow=False),
# https://www.telnote.cn/xiaohua/jiating/list_2.htm 列表页面
Rule(LinkExtractor(allow=r'https://www.telnote.cn/xiaohua/jiating/list_\d+.htm'), follow=True)
)
def parse_item(self, response):
item = {}
item['title'] = response.xpath('//div[@id="left"]/div/h1/text()').get()
item['pub_time'] = response.xpath('//div[@id="left"]/div/p/text()').get().replace("发布时间:", "")
item['content'] = ''.join(response.xpath('//div[@id="content"]/p/text()').getall()).strip()
return item
如上所示,定义了2个Rule,使用的是LinkExtractor,LinkExtractor其实就是LxmlLinkExtractor,关于LxmlLinkExtractor可以参考后面的内容。
这里简单的解释一下,第一个Rule是用来获取详情页的链接的。
allow设置为详情页链接的正则表达式就可以了。
callback用于设置处理这个连接的方法。
follow设置是否去拿这个链接页面并解析获取这个页面的链接,就是是否跟进去。
同理,第二个Rule也一样,不过第二个Rule是提取列表页的url,所以把Follow设置为True,需要跟进去。
我看了LxmlLinkExtractor的源码发现没有callable和Follow参数,但是设置了的确生效了。
7.4 数据过滤
# -*- coding: utf-8 -*-
# https://docs.scrapy.org/en/latest/topics/item-pipeline.html
import pymysql
import json
import time
class TelnotePipeline(object):
def __init__(self):
self.connection = pymysql.connect(
host='localhost',
user='tim',
password='123456',
database='test',
charset='utf8'
)
def close_spider(self, spider):
self.connection.close()
def process_item(self, item, spider):
title_ = item.get('title')
if not title_:
title_ = time.time()
_base_sql = "insert into tn(title,pub_time,content) values('{}','{}','{}')"
cursor = self.connection.cursor()
sql = _base_sql.format(item['title'], item['pub_time'], item['content'])
cursor.execute(sql)
self.connection.commit()
file_base = r"F:\tmp\scrapy\{}.txt"
with open(file_base.format(title_), encoding='utf-8', mode='w') as f:
f.write(json.dumps(item))
return item
在settings配置文件中添加过滤器配置:
# 值300表示优先级,越小优先级越高,范围:0-1000
ITEM_PIPELINES = {
'telnote.pipelines.TelnotePipeline': 300,
}
八、LxmlLinkExtractor
参数 | 类型 | 说明 |
---|---|---|
allow | 正则表达式列表 | url能够匹配就接受,如果为空,则全部接受 |
deny | 正则表达式列表 | url能够匹配就拒绝,优先级比allow高 |
allow_domains | str或list | 允许的域名 |
deny_domains | str或list | 不允许的域名 |
deny_extensions | list | 排除指定扩展名 |
restrict_xpaths | str或list | 指定提取url的xpath |
restrict_css | str或list | 指定提取url的css |
tags | str或list | 从那些标签提取url,默认(‘a’,‘area’) |
attrs | list | url标签必须包含的属性,默认(‘href’) |
canonicalize | bool | url是否必须是规范化 |
unique | bool | 是否对url去重 |
strip | bool | 是否去除url两边空格 |
process_value | callable | 使用callable处理链接值 |