点击上方蓝字关注公众号

码个蛋第262次推文

以后再也不愁看什么电影了

作者:猴哥Yuri

博客:

https://www.jianshu.com/u/f46becd1ed83

文章目录

爬取目标

设计爬虫程序

确定爬普罗米修斯 电影取入口

爬取思路

设计爬虫架构

代码实现

爬取结果

前面两篇文章介绍 requests 和 xpath 的用法。我们推崇学以致用,所以本文讲解利用这两个工具进行实战。

0

爬取目标

本次爬取的站点选择电影天堂,网址是普罗米修斯 电影: www.dytt8.net。爬取内容是整个站点的所有电影信息,包括电影名称,导演、主演、下载地址等。具体抓取信息如下图所示:

1

设计爬虫程序

2.1 确定爬取入口

电影天堂里面的电影数目成千上万,电影类普罗米修斯 电影型也是让人眼花缭乱。我们为了保证爬取的电影信息不重复, 所以要确定一个爬取方向。目前这情况真让人无从下手。但是,我们点击主页中的【最新电影】选项,跳进一个新的页面。蓦然有种柳暗花明又一村的感觉。

由图可普罗米修斯 电影知道,电影天堂有 5 个电影栏目,分别为最新电影、日韩电影、欧美电影、国内电影、综合电影。每个栏目又有一定数量的分页,每个分页有 25 条电影信息。那么程序的入口可以有 5 个 url 地址。这 5 普罗米修斯 电影个地址分别对应每个栏目的首页链接。

2.2 爬取思路

知道爬取入口,后面的工作就容易多了。我通过测试发现这几个栏目除了页面的 url 地址不一样之外,其他例如提取信息的 xpath 路径是一样的。因此,我普罗米修斯 电影把 5 个栏目当做 1 个类,再该类进行遍历爬取。

我这里“最新电影”为例说明爬取思路。

1)请求栏目的首页来获取到分页的总数,以及推测出每个分页的 url 地址;

2)将获取到的分页 url 存放到名为 普罗米修斯 电影floorQueue 队列中;

3)从 floorQueue 中依次取出分页 url,然后利用多线程发起请求;

4)将获取到的电影页面 url 存入到名为 middleQueue 的队列;

5)从 midd普罗米修斯 电影leQueue 中依次取出电影页面 url,再利用多线程发起请求;

6)将请求结果使用 Xpath 解析并提取所需的电影信息;

7)将爬取到的电影信息存到名为 contentQueue 队列中;

8)从 c普罗米修斯 电影ontentQueue 队列中依次取出电影信息,然后存到数据库中。

2.3 设计爬虫架构

根据爬取思路,我设计出爬虫架构。如下图所示:

2.4 代码实现

主要阐述几个重要的类的代码

main 类

主要工作两个:第普罗米修斯 电影一,实例化出一个dytt8Moive对象,然后开始爬取信息。第二,等爬取结束,将数据插入到数据库中。

处理爬虫的逻辑代码如下:

# 截止到2017-08-08, 最新电影一共才有 164

个页面

LASTEST普罗米修斯 电影_MOIVE_TOTAL_SUM =6 #164# 请求网络线程总数, 线程不要调太好, 不然会返回很多 400THREAD_SUM = 5

def startSpider:

# 实例化对象

# 获取【最新电影】普罗米修斯 电影有多少个页面

LASTEST_MOIVE_TOTAL_SUM = dytt_Lastest.getMaxsize

print(【最新电影】一共 + str(LASTEST_MOIVE_TOTAL_SUM) 普罗米修斯 电影+ 有个页面

)

dyttlastest = dytt_Lastest(LASTEST_MOIVE_TOTAL_SUM)

floorlist = dyttlastest.getPageUrlList

floor普罗米修斯 电影Queue = TaskQueue.getFloorQueue

for item in floorlist:

floorQueue.put(item, 3

)

# print

(floorQueue.qsize)

f普罗米修斯 电影or i in range

(THREAD_SUM):

workthread = FloorWorkThread(floorQueue, i)

workthread.start

while True:

if

Task普罗米修斯 电影Queue.isFloorQueueEmpty:

break

else:

pass

for i in range

(THREAD_SUM):

workthread = TopWorkThread(TaskQueue普罗米修斯 电影.getMiddleQueue, i)

workthread.start

while True:

if

TaskQueue.isMiddleQueueEmpty:

break

else:

pass

insertDat普罗米修斯 电影a

if __name__ == __main__

:

startSpider

创建数据库以及表,接着再把电影信息插入到数据库的代码如下:

def insertData:

DBName = dytt.db

db = 普罗米修斯 电影sqlite3.connect(./ + DBName, 10)

conn = db.cursor

SelectSql = Select * from sqlite_master where type = "table"普罗米修斯 电影 and name="lastest_moive"

;

CreateTableSql =

Create Table

lastest_moive (

m_id INTEGER PRIMARY KEY

,

m_type varcha普罗米修斯 电影r(100

),

m_trans_name varchar(200

),

m_name varchar(100

),

m_decade varchar(30

),

m_conutry varchar(30

),

m_level v普罗米修斯 电影archar(100

),

m_language varchar(30

),

m_subtitles varchar(100

),

m_publish varchar(30

),

m_IMDB_socre varchar(5普罗米修斯 电影0

),

m_douban_score varchar(50

),

m_format varchar(20

),

m_resolution varchar(20

),

m_size varchar(10

),

m_duratio普罗米修斯 电影n varchar(10

),

m_director varchar(50

),

m_actors varchar(1000

),

m_placard varchar(200

),

m_screenshot varchar(2普罗米修斯 电影00

),

m_ftpurl varchar(200

),

m_dytt8_url varchar(200

)

);

InsertSql =

Insert into

lastest_moive(m_type, m_trans普罗米修斯 电影_name, m_name, m_decade, m_conutry, m_level, m_language, m_subtitles, m_publish, m_IMDB_socre,

m_doub普罗米修斯 电影an_score, m_format, m_resolution, m_size, m_duration, m_director, m_actors, m_placard, m_screenshot,普罗米修斯 电影 m_ftpurl,

m_dytt8_url)

values

(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);

if not c普罗米修斯 电影onn.execute(SelectSql).fetchone:

conn.execute(CreateTableSql)

db.commit

print(==== 创建表成功 ====

)

else

:

prin普罗米修斯 电影t(==== 创建表失败, 表已经存在 ====

)

count = 1while not

TaskQueue.isContentQueueEmpty:

item = TaskQueue.getContentQue普罗米修斯 电影ue.get

conn.execute(InsertSql, Utils.dirToList(item))

db.commit

print(插入第 + str(count) + 条数据成功

)

count = count普罗米修斯 电影 + 1

db.commit

db.close

TaskQueue 类

维护 floorQueue、middleQueue、contentQueue 三个队列的管理类。之所以选择队列的数据结构,是因为爬虫程序需要普罗米修斯 电影用到多线程,队列能够保证线程安全。

dytt8Moive 类

dytt8Moive 类是本程序的主心骨。程序最初的爬取目标是 5 个电影栏目,但是目前只现实了爬取最新栏目。如果你想爬取全部栏目电影,只需对普罗米修斯 电影 dytt8Moive 稍微改造下即可。

class dytt_Lastest(object):

# 获取爬虫程序抓取入口

breakoutUrl = http://www.dytt8.net/html/gn普罗米修斯 电影dy/dyzz/index.html

def __init__(self, sum):

self.sum = sum

# 获取【最新电影】有多少个页面

# 截止到2017-08-08, 最新电影一共才有 164普罗米修斯 电影

个页面

@classmethod

def getMaxsize(cls):

response = requests.get(cls.breakoutUrl, headers=RequestModel.get普罗米修斯 电影Headers, proxies=RequestModel.getProxies, timeout=3

)

# 需将电影天堂的页面的编码改为 GBK, 不然会出现乱码的情况

response.encodin普罗米修斯 电影g =GBK

selector = etree.HTML(response.text)

# 提取信息

optionList = selector.xpath("//select[@name=sldd]/te普罗米修斯 电影xt"

)

return len(optionList) - 1 # 因首页重复, 所以要减1

def getPageUrlList(self):

主要功能:目录页url取出,比如:http://www.dytt8普罗米修斯 电影.net/html/gndy/dyzz/list_23_+ str(i) + .html

templist =

request_url_prefix = http://www.dytt8.net/html/g普罗米修斯 电影ndy/dyzz/templist = [request_url_prefix + index.html

]

for i in range(2, self.sum + 1

):

templist.append(req普罗米修斯 电影uest_url_prefix +list_23_ + str(i) + .html

)

for

t in templist:

print(request url is ### + t + ###

)

return

tem普罗米修斯 电影plist

@classmethod

def getMoivePageUrlList(cls, html):

获取电影信息的网页链接

selector = etree.HTML(html)

templist =普罗米修斯 电影 selector.xpath("//div[@class=co_content8]/ul/td/table/tr/td/b/a/@href"

)

# print(len

(templist))

# print

(普罗米修斯 电影templist)

return

templist

@classmethod

def getMoiveInforms(cls, url, html):

解析电影信息页面的内容, 具体如下:类型 : 疾速特攻/疾普罗米修斯 电影速追杀2][BD-mkv.720p.中英双字][2017年高分惊悚动作]◎译名 : ◎译\u3000\u3000名\u3000疾速特攻/杀神John Wick 2(港)/捍卫任务2(台)/疾速追杀2/普罗米修斯 电影极速追杀:第二章/约翰·威克2◎片名 : ◎片\u3000\u3000名\u3000John Wick: Chapter Two◎年代 : ◎年\u3000\u3000代\u30002017◎国家 :普罗米修斯 电影 ◎产\u3000\u3000地\u3000美国◎类别 : ◎类\u3000\u3000别\u3000动作/犯罪/惊悚◎语言 : ◎语\u3000\u3000言\u3000英语◎字幕 : ◎字\u30普罗米修斯 电影00\u3000幕\u3000中英双字幕◎上映日期 :◎上映日期\u30002017-02-10(美国)◎IMDb评分 : ◎IMDb评分\xa0 8.1/10 from 86,240 users◎豆普罗米修斯 电影瓣评分 : ◎豆瓣评分\u30007.7/10 from 2,915 users◎文件格式 : ◎文件格式\u3000x264 + aac◎视频尺寸 : ◎视频尺寸\u30001280 x 720◎文普罗米修斯 电影件大小 : ◎文件大小\u30001CD◎片长 : ◎片\u3000\u3000长\u3000122分钟◎导演 : ◎导\u3000\u3000演\u3000查德·史塔赫斯基 Chad Stahels普罗米修斯 电影ki◎主演 :◎简介 : 暂不要该字段◎获奖情况 : 暂不要该字段◎海报影片截图下载地址# print

(html)

contentDir = {

type

: ,

trans_name

: ,

name

: ,

dec普罗米修斯 电影ade

: ,

conutry

: ,

level

: ,

language

: ,

subtitles

: ,

publish

: ,

IMDB_socre

: ,

douban_score

: ,

format

: ,

resolu普罗米修斯 电影tion

: ,

size

: ,

duration

: ,

director

: ,

actors

: ,

placard

: ,

screenshot

: ,

ftpurl

: ,

dytt8_url

:

}

selector = e普罗米修斯 电影tree.HTML(html)

content = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/td/p/text"

)

# 匹配出来有两张普罗米修斯 电影图片, 第一张是海报, 第二张是电影画面截图

imgs = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/td/p/img/@src"

)

#普罗米修斯 电影print

(content)

# 为了兼容 2012

年前的页面

if not len

(content):

content = selector.xpath("//div[@class=co_content8]/u普罗米修斯 电影l/tr/td/div/div/td/span/text"

)

# 有些页面特殊, 需要用以下表达式来重新获取信息

# 电影天堂页面好混乱啊~

if not len

(content):

content = sele普罗米修斯 电影ctor.xpath("//div[@class=co_content8]/ul/tr/td/div/td/div/text"

)

if not len

(content):

content = selector普罗米修斯 电影.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/p/font/text"

)

if len(content) < 5

:

content = selec普罗米修斯 电影tor.xpath("//div[@class=co_content8]/ul/tr/td/p/font/text"

)

if not len

(content):

content = selector.xpat普罗米修斯 电影h("//div[@class=co_content8]/ul/tr/td/div/div/td/p/span/text"

)

if not len

(content):

content = selector.x普罗米修斯 电影path("//div[@class=co_content8]/ul/tr/td/div/div/td/div/span/text"

)

if not len

(content):

content = selec普罗米修斯 电影tor.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/font/text"

)

if not len

(content):

content = sele普罗米修斯 电影ctor.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/p/text"

)

# print

(content)

# 不同渲染页面要采取不同的抓取方式抓普罗米修斯 电影取图片

if not len

(imgs):

imgs = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/img/@src"

)

ifn普罗米修斯 电影otlen

(imgs):

imgs = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/p/img/@src"

)

if not le普罗米修斯 电影n

(imgs):

imgs = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/div/img/@src"

)

if not len

(普罗米修斯 电影imgs):

imgs = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/td/div/img/@src"

)

# 类型

if content[0普罗米修斯 电影][0:1] !=

:

contentDir[type] = [ + content[0

]

actor =

for

each in content:

if each[0:5] == ◎译\u3000\u3000名

:

# 普罗米修斯 电影译名 ◎译\u3000\u3000名\u3000 一共占居6

contentDir[trans_name] = each[6: len

(each)]

elif each[0:5] == ◎片\u3000\u普罗米修斯 电影3000名

:

# 片名

contentDir[name] = each[6: len

(each)]

elif each[0:5] == ◎年\u3000\u3000代

:

# 年份

contentDir[decade普罗米修斯 电影] = each[6: len

(each)]

elif each[0:5] == ◎产\u3000\u3000地

:

# 产地

contentDir[conutry] = each[6: len

(each)]

eli普罗米修斯 电影f each[0:5] == ◎类\u3000\u3000别

:

# 类别

contentDir[level] = each[6: len

(each)]

elif each[0:5] == ◎语\u3000\u30普罗米修斯 电影00言

:

# 语言

contentDir[language] = each[6: len

(each)]

elif each[0:5] == ◎字\u3000\u3000幕

:

# 字幕

contentDir[subt普罗米修斯 电影itles] = each[6: len

(each)]

elif each[0:5] == ◎上映日期

:

# 上映日期

contentDir[publish] = each[6: len

(each)]

elif e普罗米修斯 电影ach[0:7] == ◎IMDb评分

:

# IMDb评分

contentDir[IMDB_socre] = each[9: len

(each)]

elif each[0:5] == ◎豆瓣评分

:

# 豆瓣评分

co普罗米修斯 电影ntentDir[douban_score] = each[6: len

(each)]

elif each[0:5] == ◎文件格式

:

# 文件格式

contentDir[format] = each[6: l普罗米修斯 电影en

(each)]

elif each[0:5] == ◎视频尺寸

:

# 视频尺寸

contentDir[resolution] = each[6: len

(each)]

elif each[0:5] == ◎文件普罗米修斯 电影大小

:

# 文件大小

contentDir[size] = each[6: len

(each)]

elif each[0:5] == ◎片\u3000\u3000长

:

# 片长

contentDir[duratio普罗米修斯 电影n] = each[6: len

(each)]

elif each[0:5] == ◎导\u3000\u3000演

:

# 导演

contentDir[director] = each[6: len

(each)]

e普罗米修斯 电影lif each[0:5] == ◎主\u3000\u3000演

:

# 主演

actor = each[6: len

(each)]

for

item in content:

if item[0: 4] == \u3000普罗米修斯 电影\u3000\u3000\u3000

:

actor = actor + \n + item[6: len

(item)]

# 主演

contentDir[actors

] = actor

# 海报

if imgs[0

] !普罗米修斯 电影= None:

contentDir[placard] = imgs[0

]

# 影片截图

if imgs[1

] != None:

contentDir[screenshot] = imgs[1

]

ftp = se普罗米修斯 电影lector.xpath("//div[@class=co_content8]/ul/tr/td/div/td/table/tbody/tr/td/a/text"

)

# 为了兼容 2012

年前的页面

ifn普罗米修斯 电影otlen

(ftp):

ftp = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/table/tbody/tr/td/fon普罗米修斯 电影t/a/text"

)

if not len

(ftp):

ftp = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/table/tb普罗米修斯 电影ody/tr/td/a/text"

)

if not len

(ftp):

ftp = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/普罗米修斯 电影div/table/tbody/tr/td/font/a/text"

)

if not len

(ftp):

ftp = selector.xpath("//div[@class=co_content8]/ul/普罗米修斯 电影tr/td/div/td/div/table/tbody/tr/td/a/text"

)

if not len

(ftp):

ftp = selector.xpath("//div[@class=co_conte普罗米修斯 电影nt8]/ul/tr/td/div/td/table/tbody/tr/td/a/text"

)

if not len

(ftp):

ftp = selector.xpath("//div[@class=co_c普罗米修斯 电影ontent8]/ul/tr/td/div/div/td/p/span/a/text"

)

if not len

(ftp):

ftp = selector.xpath("//div[@class=co_cont普罗米修斯 电影ent8]/ul/tr/td/div/div/td/div/div/table/tbody/tr/td/font/a/text"

)

if not len

(ftp):

ftp = selector.xpath(普罗米修斯 电影"//div[@class=co_content8]/ul/tr/td/div/div/td/span/table/tbody/tr/td/font/a/text"

)

if not len

(ftp):

ftp普罗米修斯 电影 = selector.xpath("//div[@class=co_content8]/ul/tr/td/div/div/td/div/span/div/table/tbody/tr/td/font普罗米修斯 电影/a/text"

)

contentDir[ftpurl] = ftp[0

]

# 页面链接

contentDir[dytt8_url

] = url

print(contentDir)

returncontentD普罗米修斯 电影ir

选择字典类型作为存储电影信息的数据结构,也是自己爬坑之后才决定的。这算是该站点另一个坑人的地方。电影详情页中有些内容节点是没有,例如类型、豆瓣评分,所以无法使用列表按顺序保存。

2

爬取结果

我这里展示普罗米修斯 电影自己爬取最新栏目中 4000 多条数据中前面部分数据。

附:源代码地址(https://link.jianshu.com/?t=

https://github.com/monkey-soft/Moives普罗米修斯 电影Spider)