- 准备好数据库
#mysql
#创建库:maoyandb,创建表:filmtab
create database maoyandb charset=utf8;
create table filmtab(name varchar(100),star varchar(300),time varchar(50);
#mongodb
#mongodb数据库不需要提前创建库和集合,运行时自动创建
- 在shell中创建scrapy项目
scrapy startproject Maoyan
- 创建爬虫文件maoyan.py:scrapy genspider 爬虫名 访问的域名(不带www.)
cd Maoyan
scrapy genspiser maoyan maoyan.com
- items.py中定义要抓取的数据结构:电影名、主演、上映时间
import scrapy
class MaoyanItem(scrapy.Item)
'''定义要爬取的数据结构:名称+主演+上映时间'''
#相当于你定义了一个字典:{'name':'','star':'','time':''}
name = scrapy.Field() #Field()的内部实现就是字典
star = scrapy.Field()
time = scrapy.Field()
- 爬虫文件maoyan.py
import scrapy
from ..items import MaoyanItem #因为需要将数据通过items.py中定义的变量传给管道pipeline.py保存,所以将items.py中的MaoyanItem这个类导进来
class MaoyanSpider(scrapy.Spider):
name = 'maoyan' #爬虫名,可修改
allowed_domains = ['maoyan.com'] #域名
#scrapy源码中scrapy.Spider类写的stat_requests()一次只能给到调度器一个url,这样达不到多线程一次性抓取多个url的目的,需要在下面重写
#start_urls = ['https://maoyan.com/board/4?offset=0'] #电影排行第一页的url
#重写scrapy框架的scrapy.Spider类的start_requests()方法,不重写的话url地址只能一个个交给调度器进行请求,重写是为了将所有想请求的url一次性给到调度器入队列
def start_requests(self):
url = 'https://maoyan.com/board/4?offset={}' #排行榜url的规律是每页的offset间隔10
for offset in range(0,91,10):
page_url = url.format(offset)
#将需要请求的url交给调度器
yield scrapy.Request(
url=page_url, #传给调度器的url
callback=self.parse_html #指定请求响应回来后解析html对象的函数
)
#解析响应的函数
def parse_html(self,response):
#实例化items.py中的类:MaoyanItem获取数据结构
item = MaoyanItem()
dd_list = response.xpath('//dl[@class="board-wrapper"]/dd') #xpath表达式自己去写,返回的数据格式为['<selector data='A'>','<selector data='B'>,....]
#将解析出来的数据放到item中
for dd in dd_list:
#给Item对象的3个属性赋值,现在这个版本必须使用字典的['']
#使用get()获取xpath()返回的数据的第一个序列化的元素('字符串'),获取你要的数据
item['name'] = dd.xpath('./a/@title').get().strip()
item['star'] = dd.xpath('.//p[@class="star"']/text()).get().strip()
item['time'] = dd.xpath('.//p[@class="releasetime"]/text()').get().strip()
#循环一次,将整理好的数据提交给管道一次(这样效率高)
yield item
- 管道文件pipelines.py
import pymysql
from .settings import * #将settings.py导进来,因为在里面定义了数据库的账号信息变量,这里引用
import pymongo
#数据在终端显示的管道
class MaoyanPipeling(object):
def process_item(self,item,spider):
print(item['name'],item['time'],item['star'])
return item
#数据存入mysql的管道类
class MaoyanMysqlPipeline(object):
#open_spider方法:监听爬虫,爬虫启动时只执行1次,一般用于数据库连接
def open_spider(self,spider):
#连接数据库
self.db = pymysql.connect(
host=MYSQL_HOST,
user=MYSQL_USER,
password=MYSQL_PWD,
database=MYSQL_DB,
charset=MYSQL_CHAR
)
self.cursor = self.db.cursor()
def process_item(self,item,spider):
#sql插入语句:insert into 表名 value(字段1的值,字段2的值...)
ins = 'insert into filmtab values(%s,%s,%s)'
L = [item['name'],item['star'],item['time']
self.cursor.execute(ins,L)
self.db.commit()
return item #将item数据传入下一个要用的数据库,比如mongodb
#close_spider监听爬虫,爬虫结束时只执行1次,一般用于数据库断开
def close_spider(self,spider):
self.cursor.close()
self.db.close()
#数据存入mongodb
class MaoyanMongoPipeline(object):
#连数据库
def open_spider(self,spider):
self.conn = pymongo.MongoClient(MONGO_HOST,NONG_PORT)
self.db = self.conn[MONGO_DB] #库对象
self.myset = self.db[MONGO_SET] #集合对象
def process item(self,item,spider):
d = dict(item) #将传进来要存的数据item转为字典,其实item本质就是个字典
self.myset.inser_one(d) #将数据插入mongodb数据库
return item
- settings.py
ROBOTSTXT_OBEY = True #将君子协议置为False
#加上User-Agent
DEFAULT_REQUEST_HEADERS = {
'Accept':...,
'Accept-Laguage':..,
'User-Agent':'xxx' #去网上找一个
}
#打开管道
ITEM_PIPELINES = {'Maoyan.pipelines.MaoyanPipeline':300,
'Maoyan.pipelines.MaoyanMysqlPipeline':200, #添加的存mysql的管道,数值表示存入的优先级(先存哪个)
'Maoyan.pipelines.MaoyanMongoPipeline':249, #存mongodb的管道
}
#设置显示的日志类别
LOG_LEVEL = 'WARNING' #显示严重程度大于等于WARNING警告的日志
#设置日志不显示在终端,单独保存到log文件中
LOG_FILE = 'maoyan.log'
#定义存入mysql相关变量
MYSQL_HOST = '127.0.0.1'
MYSQL_USER = 'root'
MYSQL_PWD = '123456'
MYSQL_DB = 'maoyandb'
MYSQL_CHAR = 'utf8'
#定义mongodb常用变量
MONGO_HOST = '127.0.0.1'
MONGO_PORT = 27017 #端口
MONGO_DB = 'maoyandb' #库名
MONGO_SET = 'filmtab' #集合名
#设置存Json文件时导出的编码,不设置不能显示中文
FEED_EXPORT_ENCODING = 'utf-8'
- 在主项目目录下新建r爬虫执行文件:run.py
from scrapy import cmdline
cmdline.execute('scrapy crawl maoyan'.split())
##数据持久化:存csv文件的命令,会保存到项目下
#cmdline.execute('scrapy crawl maoyan -o maoyan.csv'.split())
##数据持久化:存json文件的命令,会保存到项目下
#cmdline.execute('scrapy crawl maoyan -o maoyan.json'.split())
-
执行
执行run.py文件,爬虫项目启动,直接找爬虫文件maoyan.py中的start_requests()执行,这个方法中直接将10个url的地址交给调度器,下载器用多线程同时下载10个html之后response,等10个response回来后找parse_html()解析函数解析(相当于parse_html()调用了10次,每次传入不同的response),解析函数使用的是协程yield,多线程+协程效率绝对高 -
额外知识点补充
- 日志(严重程度递减) :CRITICAL严重错误,ERROR普通错误,WARNING警告,INFO一般信息,DEBUG调试信息
#在settings.py中可设置显示出来的日志类别
LOG_LEVEL = 'WARNING' #表示只显示严重程度高于等于WARNING的日志类型
#在settings.py中可设置日志保存成文件,不在终端显示
LOG_FILE = 'maoyan.log'