使用Python3+scrapy爬取某电影网站数万条数据到MySQL数据库!
一、创建scrapy爬虫
1、创建项目(CMD)
注意是在CMD中使用命令,最后接创建项目的目录
一、创建scrapy爬虫 1、创建项目(CMD) 注意是在CMD中使用命令,最后接创建项目的目录 scrapy startproject mvSrc D:/damo scrapy startproject mvSrc D:/damo
2、创建爬虫文件(CMD)
- 进入项目文件夹切换盘符:D:切换到目录:cd /damo
- 创建爬虫文件命令:scrapy genspider xx xxx.cnxx是爬虫名称,xxx.cn是爬虫运行的网站的域名
scrapy genspider mvSpi 'yy6080.cn' 1
二、编写爬虫文件(pychar)
1、创建run文件
在pychar中创建run.py文件(可命名为其他),方便直接在pychar里面运行,无需到CMD当中运行
from scrapy import cmdline #mvSpi后接 --nolog,为无日志模式输出 cmdline.execute('scrapy crawl mvSpi'.split()) 123
完成后可直接在爬虫文件(mvSpi.py)中输出response.text,查看是否跑的通
class MvspiSpider(scrapy.Spider): name = 'mvSpi' allowed_domains = ['yy6080.cn'] start_urls = ['http://www.yy6080.cn/vodtypehtml/1.html'] def parse(self, response): print(response.text) 123456
2、分析网页,编写爬虫文件
(1)查看网页,确定采集内容的结构
- 查看首页
-
查看二级页面
网页结构简单,不做赘述
3、编写获取二级详情页面
def parse(self, response): print(response.text) analUrl = response.xpath('//div/a/img/../@href').extract() for url in analUrl: yield scrapy.Request('http://www.yy6080.cn'+url,callback=self.analyHtml) def analyHtml(self,response): print(response.text) 12345678
注意:运行是运行run.py文件,并非mvSpi.py文件!
(1)编写items.py文件
确认自己需要采集的信息,此次需要电影名、更新日期、分类、评分、链接地址
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://docs.scrapy.org/en/latest/topics/items.html import scrapy class MvscrItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() name = scrapy.Field() update = scrapy.Field() actor = scrapy.Field() score = scrapy.Field() mvUrl = scrapy.Field() 123456789101112131415161718
(2)解析二级页面
我使用的是正则表达式,可使用xpath或其他
- 导入库(下面步骤需要导入的库直接一并在这里导入了)
# -*- coding: utf-8 -*- import scrapy from ..items import MvscrItem import re 1234
- 编写匹配规则
class MvspiSpider(scrapy.Spider): name = 'mvSpi' allowed_domains = ['yy6080.cn'] start_urls = ['http://www.yy6080.cn/vodtypehtml/1.html'] reUrl = 'position:relative;display:block;.*?href="(.*?)"' reName = 'movie-title">(.*?)<' reUpdateTime = '更新时间:(.*?)<' reActor = '导演.*?\n.*?>.*?>(.*?)<' reScore = '评分.*?\n.*?>(.*?)<' reMvUrl = 'panel panel-default resource-list ptab ptabw.*?\n.*?\n.*?\n.*?\n.*?href="(.*?)"' reNext = '<a target="_self" href=">(.*?).*?>下一页</a>' 123456789101112
- 编写解析函数
def __init__(self): self.item = MvscrItem() def analyHtml(self,response): # print(response.text) html = response.text tmpName = re.findall(self.reName,html,re.S) if re.findall(self.reName,html,re.S) else '-' self.item['name'] = ''.join(tmpName) tmpUpdate = re.findall(self.reUpdateTime, html, re.S) if re.findall(self.reUpdateTime, html, re.S) else '-' self.item['update'] = ''.join(tmpUpdate) tmpActor = re.findall(self.reActor, html, re.S) if re.findall(self.reActor, html, re.S) else '-' self.item['actor'] = ''.join(tmpActor) tmpScore = re.findall(self.reScore, html, re.S) if re.findall(self.reScore, html, re.S) else '-' self.item['score'] = ''.join(tmpScore) tmp = re.findall(self.reMvUrl, html, re.S) if re.findall(self.reMvUrl, html, re.S) else '-' self.item['mvUrl'] = ''.join(tmp) yield self.item 1234567891011121314151617
代码解释:
tmpName = re.findall(self.reName,html,re.S) if re.findall(self.reName,html,re.S) else ‘-’
:if...esle...三目运算,防止解析的数据为空,写入数据库导致报错
self.item[‘name’] = ‘’.join(tmpName)
:''.join...拼接,有些解析出来有两个结果,比如有两个播放URL,同样是为了防止写入数据库报错
由于对接的数据库是关系型数据库,所以在爬虫解析方法上做了一些特殊处理,防止写入的数据是空数据或者列表型数据(MySQL不支持写入列表但是Mongo可以,当时给我整蒙了),如果是直接写入CSV或者非关系型数据库,analyHtml可以精简许多。
4、解析下一页,并存储
到了第(4)步,基本上就完成了大部分的解析内容,但只是首页的内容,如果需要采集所有页面的内容,还需要解析下一页的规则
简单分析发现仅仅是URL变化,直接做一个拼接即可
def parse(self, response): #print(response.text) analUrl = response.xpath('//div/a/img/../@href').extract() for url in analUrl: yield scrapy.Request('http://www.yy6080.cn'+url,callback=self.analyHtml) for i in range(2,1044):#下一页 tmpUrl = f'http://www.yy6080.cn/vodtypehtml/1-{i}.html' yield scrapy.Request(tmpUrl,callback=self.parse)#递归 12345678
(1)编写setting.py文件,异步写入数据库
由于采集的数据较多,防止拥塞影响爬虫效率,故使用异步
# mysql 配置 MYSQL_DB_NAME = 'student_db' MYSQL_HOST = '127.0.0.1' MYSQL_USER = 'root' MYSQL_PASSWORD = '1234567' 12345
(2)创建数据库
- 进入数据库
mysql -uroot -p 1
- 切换
use studen_db 1
- 创建数据库
CREATE TABLE mvtable( mv_name varchar(100), mv_update VARCHAR(200) , mv_actor varchar(200) NOT NULL, mv_score varchar(50), mv_mvUrl varchar(200), PRIMARY KEY ( mv_mvUrl ) )ENGINE=InnoDB DEFAULT CHARSET=utf8; 12345678
varchar写大点,防止出现写入失败的情况
(3)编写piplines.py文件
# -*- coding: utf-8 -*- import pymysql # Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html class MySQLPipeline(object): # 打开数据库 def open_spider(self, spider): db = spider.settings.get('MYSQL_DB_NAME','student_db') host = spider.settings.get('MYSQL_HOST', 'localhost') port = spider.settings.get('MYSQL_PORT', 3306) user = spider.settings.get('MYSQL_USER', 'root') passwd = spider.settings.get('MYSQL_PASSWORD', '1234567') self.db_conn =pymysql.connect(host=host, port=port, db=db, user=user, passwd=passwd, charset='utf8') self.db_cur = self.db_conn.cursor() # 关闭数据库 def close_spider(self, spider): self.db_conn.commit() self.db_conn.close() # 对数据进行处理 def process_item(self, item, spider): self.insert_db(item) return item #插入数据 def insert_db(self, item): values = ( item['name'], item['update'], item['actor'], item['score'], item['mvUrl'], ) sql = 'INSERT INTO mvtable VALUES(%s,%s,%s,%s,%s)' self.db_cur.execute(sql, values) 123456789101112131415161718192021222324252627282930313233343536373839404142
(4)再次编写items.py文件,打开管道
ITEM_PIPELINES = { 'mvScr.pipelines.MySQLPipeline': 300, } 123
三、运行采集
1、pychar
红色的是日志,如果在run.py中接--nolog,则直接输出结果。
2、MySQL
MySQL运行结果,只爬取了500+(我也不知道为什么乱码)
纯手打原创,欢迎探讨。源码已打包发到个人资源,免费下载。
需要源码的加群:850591259