在python文件的scripts目录下打开cmd
pip install scrapy
可能安装失败
1.scrapy是基于twisted,先下载twisted对应版本的whl文件
2.提示upgrade pip,那就python -m pip install --upgrade pip
3.或者直接安装anaconda,这是个重量级,里面啥都有,就是有点难下载
1.在当前正在使用的python项目下,或者新建一个目录
2.从该目录进入cmd窗口
-创建项目:不允许数字开头,不允许包含中文及中文符号
scrapy startproject 项目名字
-创建文件:在spiders文件夹中创建爬虫文件
cd 项目名字\项目名字\spiders
scrapy genspider 爬虫文件名字 要爬取的网页(域名)
基于Twisted的异步处理框架
数据流:
小介绍:
-name:每个项目唯一的名字,用来区分不同的Spider
-allowed_domains:允许爬取的域名,如果初始或后续的请求链接不是这个域名下的,则请求链接会被过滤掉
-start_urls:包含Spider在启动时爬取的url列表,初始请求由他来定义
-parse:Spider的一个方法。默认情况下,被调用时start_urls里面的链接构成的请求完成下载执行后,返回的响应就会作为唯一的参数传递给这个函数。然后该方法解析返回的响应,提取数据或者进一步生成要处理的请求
import scrapy
from scr_piao_01.items import ScrPiao01Item
class BaiduSpider(scrapy.Spider):
# 爬虫的名字 用于运行爬虫的时候 使用的值
name = 'baidu'
# 允许访问的域名
allowed_domains = ['category.dangdang.com']
# 起始的url地址(第一次要访问的域名)
start_urls = ['http://category.dangdang.com/cp01.01.08.00.00.00.html']
base_url = 'http://category.dangdang.com/pg'
page = 1
# 方法中的返回对象response相当于response=urllib.request.urlopen()
def parse(self, response):
# 所有的selector对象,都可以再次调用xpath方法,extract_first()获取selector列表的第一个元素
li_lst = response.xpath('//ul[@id="component_59"]/li')
for li in li_lst:
src = li.xpath('.//img/@data-original').extract_first()
if src:
src = src
else:
src = li.xpath('.//img/@src').extract_first()
alt = li.xpath('.//img/@alt').extract_first()
price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
book = ScrPiao01Item(src=src, name=alt, price=price)
yield book
if self.page < 100:
self.page += 1
url_next = self.base_url + str(self.page)+'-cp01.01.08.00.00.00.html'
yield scrapy.Request(url=url_next, callback=self.parse)
item是保存爬取的容器,它的使用方法和字典类似。多了额外的保护机制,可以避免拼写错误或者定义字段错误。
创建item需要继承scrapy.Item类。并且定义类型为scrapy.Field的字段
class ScrPiao01Item(scrapy.Item):
src = scrapy.Field()
name = scrapy.Field()
price = scrapy.Field()
通过管道存储数据到文件或数据库
class ScrPiao01Pipeline:
def open_spider(self, spider):
self.fp = open('book.json', 'w', encoding='utf-8')
def process_item(self, item, spider):
# with open('book.json', 'a', encoding='utf-8')as fp:
# fp.write(str(item))
self.fp.write(str(item))
return item
def close_spider(self, spider):
self.fp.close()
上面这个只爬取了初始页面的60条数据,对于下一页或者后面的数据怎么获取呢?
首先从当前页面中找到下一页的请求信息,然后在下一个请求的页面里找到信息再构造下下一个请求,一直迭代下去,就实现整站的爬取啦!
先瞅瞅那个每页的url
构造请求时要用到scrapy.Request
构造请求时要用到scrapy.Request,传递的参数
-url:请求链接
-callback:回调函数,当指定了该回调函数的请求完成==>获取到响应==>引擎再将该响应传递给这个回调函数
要注意allowed_domains
crawlspider为全站爬取而生的。CrawlSpider可以定义规则,在解析HTML内容的时候,根据规则提取指定的链接,然后再向这些链接发送请求。
# 模拟用法
link01 = LinkExtractor(allow=r'**************')
link02 = LinkExtractor(restrict_xpaths=r'**************')
link02 = LinkExtractor(restrict_css=r'**************')
# 提取链接
link.extract_links(response)
创建项目及文件
-scrapy startproject dushuproject
-cd dushuproject\dushuproject\spiders
-scrapy genspider -t crawl xiaoye https://www.dushu.com/book/1617.html
这里有个不大不小的大坑~~
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from dushuproject.items import DushuprojectItem
class XiaoyeSpider(CrawlSpider):
name = 'xiaoye'
allowed_domains = ['www.dushu.com']
start_urls = ['https://www.dushu.com/book/1617.html']
# 把follow改成True,会按照链接提取的规则自动跟进。把所有页面的数据都给他薅下来
rules = (
Rule(LinkExtractor(allow=r'/book/1617_\d+\.html'),
callback='parse_item',
follow=False),
)
def parse_item(self, response):
img_lst = response.xpath('//div[@class="bookslist"]//img')
for img in img_lst:
name = img.xpath('./@alt').extract_first()
src = img.xpath('./@data-original').extract_first()
book = DushuprojectItem(name=name, src=src)
yield book
class DushuprojectItem(scrapy.Item):
name = scrapy.Field()
src = scrapy.Field()
class DushuprojectPipeline:
def open_spider(self, spider):
self.fp = open('book.json', 'w', encoding='utf-8')
def process_item(self, item, spider):
self.fp.write(str(item))
return item
def close_spider(self, spider):
self.fp.close()
那个不大不小的大坑在这里~
start_urls = ['https://www.dushu.com/book/1617.html']
那个规则rules里面的LinkExtractor(allow=r'/book/1617_\d+\.html')的正则表达式是从第2页开始的,那么首页start_urls不在规则里面可不就获取不到了么
-> start_urls = ['https://www.dushu.com/book/1617_1.html']
注意
/*先进入MySQL创建数据库和要用的表*/
create database spider01 charset=utf8;
use spider01;
create table book(
id int primary key auto_increment,
name varchar(128),
src varchar(128));
DB_HOST = 'localhost'
DB_PORT = 3306
DB_USER = 'root'
DB_PASSWORD = 'xiaoye777'
DB_NAME = 'spider01'
DB_CHARSET = 'utf8'
# 给入库加条管道
ITEM_PIPELINES = {
'dushuproject.pipelines.DushuprojectPipeline': 300,
# MysqlPipeline
'dushuproject.pipelines.MysqlPipeline': 301
}
# 导入settings中的数据
from scrapy.utils.project import get_project_settings
import pymysql
class MysqlPipeline:
def open_spider(self, spider):
settings = get_project_settings()
self.host = settings['DB_HOST']
self.port = settings['DB_PORT']
self.user = settings['DB_USER']
self.password = settings['DB_PASSWORD']
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.password,
db=self.name,
charset=self.charset
)
self.cursor = self.conn.cursor()
def process_item(self, item, spider):
sql = 'insert into book(name,src) values("{}","{}")'.format(item['name'],item['src'])
self.cursor.execute(sql)
self.conn.commit()
return item
def close_spider(self, spider):
self.cursor.close()
self.conn.close()