爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 20611|回复: 10

[源代码] 爬虫实战详解:scrapy获取电影名单

[复制链接]

新浪微博达人勋

发表于 2021-1-7 10:52:15 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册 新浪微博登陆

x
一、爬虫项目设计与搭建

电影天堂是个下载电影的好去处,它有2个网址:

https://www.dy2018.com/?jdfwkey=1vljy2
https://www.dytt8.net/index.htm

(注意,这个2个网页的编码都是GB2312,获取网页时避免乱码)
这2个网页都有“新片精品”板块,作为练手,我们就从这里爬取电影名及其年份。


360截图20210107105011444.jpg


我们把整个项目命名为getFilms,项目文件夹就放在G盘的根目录吧,
在命令行新建scrapy项目:
G: 进入G盘根目录
scrapy startproject getFilms 新建项目



然后,创建2个爬虫:
www.dy2018.com的爬虫名spider_dy2018
www.dytt8.net的爬虫名spider_dytt8

命令行执行代码:
cd getFilms 进入项目目录
scrapy genspider spider_dy2018 dy2018.com 新建一个爬虫
scrapy genspider spider_dytt8 dytt8.net 新建一个爬虫


这时,就生成了爬虫目录结构:
爬虫项目结构.jpg
其中《getFilms项目介绍.txt》是我自己添加的,用来记录项目里的问题和心得。


scrapy是一个“爬虫框架”,它给了基本的文件,之后轮到我们修改文件内容来实现自己的目的。
我们需要修改的文件是:
items.py---需要爬的内容
settings.py---爬虫设置,包括伪装User-Agent
pipelines.py---获取的内容怎么处理,例如写成文件或写进数据库
2个爬虫文件:spider_dy2018.py和spider_dytt8.py---解析若干网页,获取内容


接下来,介绍下每个文件的修改方法......

密码修改失败请联系微信:mofangbao

新浪微博达人勋

 楼主| 发表于 2021-1-7 10:57:07 | 显示全部楼层
二、items.py

内容如下,极其简单!每个项目照葫芦画瓢即可。其实就是把变量写成对象的形式,方便框架的不同文件之间交流

import scrapy
class GetproxyItem(scrapy.Item):
     filmname = scrapy.Field()#电影名
     filmyear = scrapy.Field()#年份





密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-7 11:03:54 | 显示全部楼层
三、settings.py

内容如下:

BOT_NAME = 'getFilms'  #不用改
SPIDER_MODULES = ['getFilms.spiders'] #不用改
NEWSPIDER_MODULE = 'getFilms.spiders' #不用改
ROBOTSTXT_OBEY = True

#要把pipelines.py文件加进来:
ITEM_PIPELINES = {
    'getFilms.pipelines.GetfilmsPipeline': 300,
}

#用360浏览器伪装User-Agent:
USER_AGENT='Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)'

#实例:https://www.tianqi.com/wuhan/
#该网站以默认User-Agent访问会返回403,以以上User-Agent访问则状态码=200正常



密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-7 11:07:13 | 显示全部楼层
四、pipelines.py

把结果写入txt文件,
其实看代码就会发现,里面的方法process_item可以随便改,数据怎么保存都行

内容如下:

class GetfilmsPipeline(object):
    def process_item(self, item, spider):
        fileName = 'films.txt'
        with open(fileName, 'a') as fp:
            fp.write("%s%s\n"%(item['filmname'],item['filmyear']))
        return item

密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-7 11:17:03 | 显示全部楼层
五、spider_dy2018.py

这是个爬虫文件,熟悉了它的固定结构后会发现,
它的主要工作是解析一个或若干网页,然后把结果追加到items列表里,
元素定位使用的是XPath选择器,选择器语句来由以后楼层还有分析。

内容如下:

import scrapy
from getFilms.items import GetproxyItem
from scrapy.selector import Selector

class SpiderDy2018Spider(scrapy.Spider):
    name = 'spider_dy2018'
    allowed_domains = ['dy2018.com']
   
    #如果多个网页的结构类似,都能用同一套方法获得信息,那就写在start_urls里,不然就得用多个爬虫
    start_urls = ['http://dy2018.com/']


    def parse(self, response):
        x=response.text
        
        items = []


        for i in range(2,16):
            item = GetproxyItem()
            
            XPathPos='//*[@id="header"]/div/div[3]/div[4]/div[1]/div[2]/ul/li['+str(i)+']/a/text()'
            y=Selector(text=x).xpath(XPathPos).extract()
            if y==[]:
                continue
            y=y[0]
            filmyear=y[0:4]
            cut=y.split('《')
            y=cut[-1]
            cut=y.split('》')
            filmname=cut[0]
            item['filmname']=filmname
            item['filmyear']=filmyear            
            items.append(item)
        return items

密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-7 11:20:01 | 显示全部楼层
六、spider_dytt8.py

与spider_dy2018.py雷同,主要是修改下XPath语句

内容如下:

import scrapy
from getFilms.items import GetproxyItem
from scrapy.selector import Selector

class SpiderDytt8Spider(scrapy.Spider):
    name = 'spider_dytt8'
    allowed_domains = ['dytt8.net']
   
    #如果多个网页的结构类似,都能用同一套方法获得信息,那就写在start_urls里,不然就得用多个爬虫
    start_urls = ['https://www.dytt8.net/index.htm']


    def parse(self, response):


        x=response.text
        
        items = []


        for i in range(2,17):
            item = GetproxyItem()
            
            XPathPos='/html/body/div[1]/div/div[3]/div[2]/div[2]/div[1]/div/div[2]/div[2]/ul/table/tr['+str(i)+']/td[1]/a[2]/text()'
            y=Selector(text=x).xpath(XPathPos).extract()
            print(y)
            if y==[]:
                print('空!')
                continue
            y=y[0]
            filmyear=y[0:4]
            cut=y.split('《')
            y=cut[-1]
            cut=y.split('》')
            filmname=cut[0]
            item['filmname']=filmname
            item['filmyear']=filmyear
            print(filmname)            
            items.append(item)
        return items


密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-7 11:36:24 | 显示全部楼层
关键问题:网页访问成败测试与解决

项目新建后,可以在命令行测试网页是否能顺利访问,
例如:
进入项目目录后,执行:
scrapy shell www.baidu.com
正常的话response=200

访问失败的话,考虑3个问题:

1、IP被封
在浏览器打开网页,和用scrapy shell xxx使用的是同一IP,如果浏览器能打开,scrapy打不开说明不是IP被封。
IP被封对策:重启路由器,光猫换IP(书上说的,未测试)

2、cookie
需要登录的网页才涉及cookie

3、User-Agent
scrapy有默认headers,但与浏览器的headers有区别,有些网站会通过headers识别爬虫我遇到的这个网页是会通过User-Agent拦截爬虫的:https://www.tianqi.com/wuhan/
该网站以scrapy项目默认的User-Agent访问会返回状态码403

这种情况,只需要给scrapy一个浏览器的headers就可以破解,方法如下:
在settings.py中设置伪装
USER_AGENT='Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)'
然后再执行scrapy shell www.tianqi.com/wuhan/,就会返回状态码200

温馨提示:最好使用本机浏览器的headers因为不同浏览器可能有不同网页呈现,对照本机浏览器上的网页结构来写爬虫,自然要一样才行




密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-7 11:43:31 | 显示全部楼层
本帖最后由 15195775117 于 2021-1-7 12:25 编辑

XPath选择器语句

定位所需元素,是靠观察规律。按F12查看网页结构,光标在标签上过,左侧对应网页元素会闪,
右击标签可复制其各种语法下的位置语句:
1933414489.jpg

观察dy2018网站的电影名与年份所在字符串的XPath位置:
/html/body/div[2]/div/div[3]/div[4]/div[1]/div[2]/ul
/html/body/div[2]/div/div[3]/div[4]/div[1]/div[2]/ul/li[2]/a
/html/body/div[2]/div/div[3]/div[4]/div[1]/div[2]/ul/li[3]/a
...
/html/body/div[2]/div/div[3]/div[4]/div[1]/div[2]/ul/li[15]/a


总结公式:i=2,3,4,...,15
'/html/body/div[2]/div/div[3]/div[4]/div[1]/div[2]/ul/li['+str(i)+']/a'


观察dytt8.net中电影名与年份所在字符串的XPath位置:
/html/body/div[1]/div/div[3]/div[2]/div[2]/div[1]/div/div[2]/div[2]/ul/table/tbody/tr[2]/td[1]/a[2]
/html/body/div[1]/div/div[3]/div[2]/div[2]/div[1]/div/div[2]/div[2]/ul/table/tbody/tr[3]/td[1]/a[2]
/html/body/div[1]/div/div[3]/div[2]/div[2]/div[1]/div/div[2]/div[2]/ul/table/tbody/tr[4]/td[1]/a[2]
......
/html/body/div[1]/div/div[3]/div[2]/div[2]/div[1]/div/div[2]/div[2]/ul/table/tbody/tr[16]/td[1]/a[2]

总结公式:i=2,3,4,...,16
'/html/body/div[1]/div/div[3]/div[2]/div[2]/div[1]/div/div[2]/div[2]/ul/table/tbody/tr['+str(i)+']/td[1]/a[2]'



通过XPath解析时,发现<tbody>标签需要去掉才能正常读!
参考资料:scrapy关于tbody标签的问题


即公式改为:i=2,3,4,...,16
'/html/body/div[1]/div/div[3]/div[2]/div[2]/div[1]/div/div[2]/div[2]/ul/table/tr['+str(i)+']/td[1]/a[2]'





密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-7 12:31:45 | 显示全部楼层
运行爬虫

结束了以上的文件修改后,就可以运行爬虫了
命令行执行:
scrapy crawl spider_dy2018
scrapy crawl spider_dytt8
结束后发现,项目目录中多了films.txt文件,这是由pipelines.py保存的
360截图20210107123108917.jpg

密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-1-7 12:50:47 | 显示全部楼层
疑惑与反思

回顾整个scrapy项目,感觉想要达到目的,其实只需要直接解析网页即可,那为什么要用scrapy这个大黑箱呢?

这主要是因为性能问题。

爬取少量数据,固然可以使用基础工具搞定,但数据量大起来,事情就变得复杂了:

scrapy的主要性能优势:
1)scrapy使用twisted异步网络框架,类似nodejs,性能高;
2)scrapy内置的selector比beautifulsoup效率要高很多;

事实上,在Python爬虫中:requests + selenium可以解决目前90%的爬虫需求。


那么我想,以scrapy来访问、解析网页,以selenium与网页交互的scrapy+selenium模式,可能是最佳的搭配?
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表