一 【學(xué)習(xí)目標】
- 創(chuàng)建一個Scrapy項目
- 定義提取的結(jié)構(gòu)化數(shù)據(jù)Item
- 編寫爬蟲網(wǎng)頁的Spider并提取出結(jié)構(gòu)化數(shù)據(jù)Item
- 編寫Item Pipelines 來存儲提取的Item數(shù)據(jù)(可以存儲到MySQL或Redis)
二 【新建一個新的項目】
- 新建一個項目,并進入項目目錄陪拘。
scrapy startproject mySpider
cd mySpider
項目中文件的作用:
- scrapy.cfg : 項目的配置文件
- mySpider:項目的模塊槐瑞,放項目相關(guān)的代碼文件
- mySpider/items.py:項目的數(shù)據(jù)機構(gòu)存儲文件
- mySpider/pipelines.py:項目的管道文件
- mySpider/settings.py:項目的設(shè)置文件
- mySpider/spiders:放置爬蟲程序的目錄,多個爬蟲就多個子目錄
三【設(shè)置數(shù)據(jù)結(jié)構(gòu)】
這里我打算取的地址是:
http://www.dytt8.net/html/gndy/dyzz/list_23_1.html
獲取所有電影的標題区赵、鏈接愉烙、描述和下載地址
打開mySpider目錄下的Items.py
定義電影的結(jié)構(gòu)化數(shù)據(jù)的字段减牺,用于保存獲取到的數(shù)據(jù)页徐。
可以通過創(chuàng)建一個scrapy Item 類苏潜,并且類型為Scrapy.Field來定義一個Item。
4.下面我們創(chuàng)建一個MyspiderItem和構(gòu)建Item的屬性变勇。
import scrapy
class MyspiderItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field()
link = scrapy.Field()
desc = scrapy.Field()
download_url = scrapy.Field()
pass
四【制作爬蟲】
1.創(chuàng)建一個爬蟲文件
scrapy genspider movie www.dytt8.net
2.修改spider/movie.py 文件,內(nèi)容如下:
# -*- coding: utf-8 -*-
import scrapy
class MovieSpider(scrapy.Spider):
name = 'movie'
allowed_domains = ['www.dytt8.net']
start_urls = ['http://www.dytt8.net/']
def parse(self, response):
pass
這個文件也可以手動創(chuàng)建恤左,用命令比較方便一些。
name : 這個是爬蟲的名稱搀绣,必須唯一飞袋。
allow_domains : 是允許的域名范圍,是一個列表類型链患,可以設(shè)置多個域名巧鸭,表示爬蟲只能爬取允許域名下URL。
start_urls : 爬蟲從這里定義的URL開始爬取網(wǎng)頁麻捻。
parse(self,response) : 爬取網(wǎng)頁后纲仍,使用這個方法來處理爬取后獲取的網(wǎng)頁內(nèi)容。
a. 提取頁面數(shù)據(jù)組裝結(jié)構(gòu)化數(shù)據(jù)Item
b.獲取下一個需要爬取的URL
3.在start_urls里加入一個需要爬取的url地址
start_urls = ['http://www.dytt8.net/html/gndy/dyzz/index.html']
- 修改parse方法
def parse(self, response):
with open("movie_items.html","w") as fp:
fp.write(response.text)
pass
5.運行一下items爬蟲
scrapy crawl movie
會生成movie_items.html頁面
- 取結(jié)構(gòu)化數(shù)據(jù)
一般使用xpath,教程參考:http://www.w3school.com.cn/xpath/index.asp
修改movie.py爬蟲文件
# -*- coding: utf-8 -*-
import scrapy
from mySpider.items import MyspiderItem
import json
import time
import time
class MovieSpider(scrapy.Spider):
name = 'movie'
page = 1
base_url = "http://www.dytt8.net"
list_base_url = base_url + '/html/gndy/dyzz/list_23_'
allowed_domains = ['www.dytt8.net']
start_urls = [list_base_url + "%s.html" % page]
#電影列表回調(diào)方法
def parse(self, response):
#通過xpath獲取電影列表
titlelist = response.xpath('//table[@class="tbspan"]')
for movie in titlelist:
item = MyspiderItem()
title = movie.xpath("./tr[2]/td[2]/b/a/text()").extract() #通過子節(jié)點提取標題
link = movie.xpath("./tr[2]/td[2]/b/a/@href").extract()#通過子節(jié)點提取詳情url
desc = movie.xpath("./tr[4]/td/text()").extract() #通過子節(jié)點提取電影描述
item['title'] = title[0] #提取后是一個只有一個元素的列表類型芯肤,所以提取第0個元素
item['link'] = self.base_url + link[0]
item['desc'] = desc[0]
item['download_url'] = ''
yield item
#通過 item['link'] 屬性獲取詳情頁巷折,處理方法為self.parse_detail
yield scrapy.Request(item['link'],callback=self.parse_detail)
#繼續(xù)爬取下一頁以及后面的頁面,一共3頁
if self.page < 3:
self.page = self.page + 1
page_url = self.list_base_url + "%s.html" % self.page
print("---------------------------page number url ----------------------------")
print(page_url)
yield scrapy.Request(page_url, callback=self.parse)
# 電影詳情回調(diào)方法
def parse_detail(self,response):
time.sleep(2)
#通過xpath獲取電影詳情里的下載地址
download_url = response.xpath('//*[@id="Zoom"]//table[1]//td/a/@href').extract()
print("---------------------------detail download_url----------------------------")
print("---------------------------" + download_url[0] + "----------------------------")
item = MyspiderItem()
item['link'] = response.url
item['download_url'] = download_url[0]
return item
- 保存數(shù)據(jù)
創(chuàng)建表:
DROP TABLE IF EXISTS `movies`;
CREATE TABLE `movies` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(50) NOT NULL DEFAULT '',
`link` varchar(200) NOT NULL DEFAULT '',
`desc` varchar(1024) NOT NULL DEFAULT '',
`download_url` varchar(500) DEFAULT '',
PRIMARY KEY (`id`),
KEY `link` (`link`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
然后修改pipelines.py管道文件
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import json
import pymysql
import redis
import jieba
from collections import Counter
class MyspiderPipeline(object):
def __init__(self):
self.id = 1;
#鏈接數(shù)據(jù)庫
self.db = pymysql.connect("localhost", "root", "root", "test", charset='utf8')
#獲取游標
self.cursor = self.db.cursor()
#鏈接redis
self.redisClient = redis.Redis(host="127.0.0.1", port=6379)
def process_item(self, item, spider):
dictitem = dict(item)
#通過download_url判斷,如果是詳情頁獲取的item崖咨,把獲取到的電影下載地址download_url更新到mysql數(shù)據(jù)庫
if dictitem['download_url']:
link = dictitem['link']
download_url = dictitem['download_url']
sql = "UPDATE movies SET `download_url` = '%s' WHERE `link` = '%s'" \
% (download_url, link)
self.cursor.execute(sql)
# 如果是電影列表獲取的item锻拘,把獲取到的title,link,desc插入到mysql數(shù)據(jù)庫
else:
title = dictitem['title']
link = dictitem['link']
desc = dictitem['desc']
sql = "INSERT INTO movies(`title`,`link`,`desc`) \
VALUES ('%s', '%s', '%s')" % \
(title, link, desc)
self.cursor.execute(sql)
last_id = self.cursor.lastrowid #獲取最后一次插入的主鍵id
#用jieba對title進行分詞,把分詞和結(jié)果和主鍵的保存到redis的set數(shù)據(jù)類型里击蹲,用于搜索
data = jieba.cut(title)
data = dict(Counter(data))
for k, v in data.items():#循環(huán)所有分詞
word = k.encode('utf-8')
self.redisClient.sadd(word, last_id)#保存每個分詞和id的對應(yīng)關(guān)系
print("--------------------------- process_item sql ----------------------------")
print(sql)
self.db.commit()
return item
需要安裝第三方模塊:
pip install pymysql
pip install redis
pip install jieba