大家好,我是python的初学者,我最近在学习Scrapy管道下载时遇到很多问题,最终虽没有完全克服,但也是收获颇丰,下面我将最近遇到并克服的问题与大家分享一下!
本文的基础是pycharm,scrapy以及xpath
首先,先创建scrapy文件夹;
打开Win+R后输入cmd进入命令提示符。找到你常用的文件夹,这里找到文件夹有两种方法:
1.你可以直接输入文件夹路径名,如:cd+空格+路径
2.如果文件名过长那么可以直接找到文件夹,将文件夹直接拖动到 cd+空格后面,效果如下图:
点击回车进入文件夹并创建你的新文件
在文件夹下输入:scrapy startprojec 文件名 网址
需注意的是文件名不能以数字开头,且不能出现中文
回车打开文件进入文件中的spiders文件中,这里我还是建议cd+空格+拖动,因为这种方法确实快,文件夹也不用关闭,后面查看文件也更方便
在spiders文件夹中创建,输入scrapy genspider+空格+名字+空格+网址,效果如下
提前声明:运行spider文件要在命令提示符中输入scrapy crawl 文件名,在pycharm中是无法运行的。
创建好后进入文件你可以看到已经创建好的 class MovieSpider,其中有三个参数分别是:
1.name 2.allowed_domains 这个值一般是start_urls去掉http:或者https:后的值,但也有可能是被更改后的值,本次使用的就是电影天堂主页地址去掉http:的值,后面会进行讲解。 3.start_urls 起始的url,简单易懂
在创建spider项目时,我们传入的是电影天堂的首页的url,你可以试试直接传入最新电影页面的url,我传入后文件里的allowed_domains和start_urls的依旧是主页url,而我学习的老师的结果却是传入的url,这个问题至今没解决,可能是版本更新后就是这样,如有解决方法请不吝赐教!
检查Robots协议,先随意在文件中输入一串字符,只要方便查看即可,在命令提示符中输入scrapy crawl movie<--(这是我的文件名),如果能看到说明网站不需要遵循robots协议;如果不能输出就进入spiders文件下的settings文件中找到 ROBOTSTXT_OBEY = True,将True改为Flase或者直接Ctrl+/注销掉就好了
在class下创建方法,我先奉上代码在进行讲解(ps:这只是部分代码,所有代码我在文末上传):
def parse(self, response):
# 要第一个的名字和第二个的图片
a_list = response.xpath('//div[@class="co_content8"]//td[2]//a')
for a in a_list:
name = a.xpath('./text()').extract_first()
href = a.xpath('./@href').extract_first()
# 第二页的地址是
url = 'https://www.ygdy8.net' + href
# 对第二页发起访问
yield scrapy.Request(url=url, callback=self.parse_second, meta={'name': name})
def parse_second(self, response):
# 原本//div[@id="Zoom"]//span/img/@src span不能加,只能慢慢试
src = response.xpath('//div[@id="Zoom"]//img/@src').extract_first()
pic = response.xpath('//div[@id="Zoom"]//img/@src').extract_first()
# 接受meta参数
name = response.meta['name']
movie = ScrapyMovie60Item(src=src, name=name,pic=pic)
yield movie
本次爬虫的目的是获取爬取前十页的电影的电影名,图片地址以及下载图片
1.首先进入网页-检索-运用xpath找到我们需要的信息,名字以及下一页的网页,由于大部分是相同的,因此先用a_list接收一部分,从检索中可以看到地址是不完整的,因此用url接收完整的地址。
2.yield的作用与return类似,我们将url传入下一个函数,callback=self.parse_second意思是传入到parse_second,需要注意的是meta是以字典形式传递数据
3.进入parse_second后接收数据,可以看到我的是src和pic的传入是一样的,因为我不仅要图片的网址,还需要下载图片,在后面管道下载时分别下载即可
4.movie是对数据的封装,打开spiders文件下的文件items,输入需要封装的值,名字可以自己取
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class ScrapyMovie60Item(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
name=scrapy.Field()
src=scrapy.Field()
pic=scrapy.Field()
pass
只有class下的非注释内容需要自己写;需要注意的是,要使用封装需要传入一段代码在题头,不然会报错,scrapy_movie_60.items 就是之前创建的文件夹名+.items,后面的ScrapyMovie60Item从items文件复制过来就行了,这时候下面不会报错而这里会报错,不用管,能正常使用!
from scrapy_movie_60.items import ScrapyMovie60Item
5.最后返回封装后的yield即可
下面编辑传输管道
进入pipelines文件,提前写入import urllib.request
# 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
# useful for handling different item types with a single interface
import urllib.request
from itemadapter import ItemAdapter
class ScrapyMovie60Pipeline:
def open_spider(self, spider):
self.fp = open('movie.json', 'w', encoding='utf-8')
def process_item(self, item, spider):
self.fp.write(str(item))
return item
def close_spider(self, spider):
self.fp.close()
class MovieDownloadPipeline:
def process_item(self, item, spider):
url = item.get('pic')
filename = './movie pic/' + item.get('name') + '.jpg'
urllib.request.urlretrieve(url=url, filename=filename)
return item
可见我开启的两条管道,第一条下载名字和图片地址,第二条下载图片
1.第一条管道首先创建了名为movie.json的json文档,然后写入下载文件,最后关闭文件。
2.第二条管道接收到了图片的地址,编辑文件名以及下载到的文件夹,特别说明:movie pic文件夹是我自己创建到spiders下的,如果不提前创建就不会进行下载,最后传值下载即可。
想使用管道还需最后一步:开启管道
进入settings找到 ITEM_PIPELINES,原本就有一条管道,再添加一条下载图片的管道即可
ITEM_PIPELINES = {
'scrapy_movie_60.pipelines.ScrapyMovie60Pipeline': 300,
'scrapy_movie_60.pipelines.MovieDownloadPipeline': 301
}
后面的数字是优先级,值越小优先级越高。
此时,已经一切就绪,先奉上所有代码:
movie文件:
import scrapy
from scrapy_movie_60.items import ScrapyMovie60Item
class MovieSpider(scrapy.Spider):
name = 'movie'
allowed_domains = ['www.ygdy8.net']
start_urls = ['https://www.ygdy8.net/html/gndy/dyzz/list_23_1.html']
base_url = 'https://www.ygdy8.net/html/gndy/dyzz/list_23_'
page = 1
def parse(self, response):
# 要第一个的名字和第二个的图片
a_list = response.xpath('//div[@class="co_content8"]//td[2]//a')
for a in a_list:
name = a.xpath('./text()').extract_first()
href = a.xpath('./@href').extract_first()
# 第二页的地址是
url = 'https://www.ygdy8.net' + href
# 对第二页发起访问
yield scrapy.Request(url=url, callback=self.parse_second, meta={'name': name})
def parse_second(self, response):
# 原本//div[@id="Zoom"]//span/img/@src span不能加,只能慢慢试
src = response.xpath('//div[@id="Zoom"]//img/@src').extract_first()
pic = response.xpath('//div[@id="Zoom"]//img/@src').extract_first()
# 接受meta参数
name = response.meta['name']
movie = ScrapyMovie60Item(src=src, name=name,pic=pic)
yield movie
if self.page < 10:
self.page = self.page + 1
url = self.base_url + str(self.page) + '.html'
# 调用parse方法
# callback是你要执行的那个方法
yield scrapy.Request(url=url, callback=self.parse)
其他的上面都有完整的,下面开始运行,在命令提示符spiders文件下输入scrapy crawl movie
这一步我遇到了还未解决的问题
1.例如:报错
2.重复出现
最后可以下载图片205张,有部分下载不了,虽然显示的是路径问题,但是可以下载,应该不是路径问题
这些问题都未解决,如有头绪,请不吝赐教!