前言 既上一篇文章之后发现自己对scrapy的爬取流程还是不太理解,于是自己做了个小脚本用来练习。因为爬取到信息较少,但是涉及的功能没有减少,因此也更直观更好理解了。
昨天运行成功了就没管,今天想记录一下的时候,发现….要爬取的网站炸了。
锁定爬取网站
name: 可以理解为爬虫的名字
allowed_domains:过滤机制,可以在爬取过程中过滤掉不是这个域名的网页,但不会对start_urls生效
start_urls:顾名思义,第一个爬取的网页
parse:链接处理,如果有多个主页面的话可以用循环批量处理,但这次的目标只有一个页面,因此直接调用parse_list处理了关于yield: 简单说就是一个不终止当前方法的 return ,将参数传给后面的函数(如下面的scrapy.Request)处理,而自己接着完成未完成的任务。
关于信息传递: 这个问题困扰了我很久,一直想知道scrapy中不同的函数(方法)是怎么联系起来共同处理一件事情的?其实根本还在于yield(当然我现在也没理解透彻)。仔细观察就能发现yield scrapy.Request(url=url,callback=self.parse_list)其是包含的信息很多,首先通过Request获取网页并解析,再通过callback调用响应函数并将解析的网页传递过去,从而完成各函数间的调用。
1 2 3 4 5 6 7 8 class MovieSpider (scrapy.Spider ): name = 'movie' allowed_domains = ['www.oeecc.com' ] start_urls = ['http://www.oeecc.com/music/' ] def parse (self, response ): url = "http://www.oeecc.com/list/top.html" yield scrapy.Request(url=url,callback=self.parse_list)
爬取主页面信息
这里使用的爬取数据方法时Xpath,在网页检查,找到要爬取的信息,复制xpath即可(如下图)
通过观察网页可以知道,每个歌曲的信息都被存储在一个li标签中
我们经过xpath筛选可以得到n个li标签以及里面的内容,因此通过循环取出单个li标签,再次筛选出我们需要的信息即可。
因为我要爬取的是歌曲链接,因此我提取的是二级网页的链接
1 2 3 4 5 6 7 def parse_list (self, response ): li_list = response.xpath('/html/body/div[2]/div[3]/ul/li' ) for li in li_list: url =li.xpath('a/@href' ).extract_first() url = 'http://www.oeecc.com' + url urllist.append(url) yield scrapy.Request(url=url,callback = self.parser_info)
爬取二级网页
通过上个函数的yield scrapy.Request(url=url,callback = self.parser_info),可以知道它将二级网页的url解析并传递到了parser_info中,下面就是parser_info的内容
1 2 3 4 5 6 7 def parser_info (self, response ): info = MusicItem() info['title' ] = response.xpath('/html/body/div[2]/div[2]/div[1]/div[2]/h1/a/text()' ).extract_first() url_initially = response.xpath('/html/body/div[2]/div[2]/div[3]/p[2]' ).extract_first() url_final = re.findall(r'value="(.*?)"' , url_initially, re.S) info['url' ] = url_final yield info
具体步骤和主页面相似,re.findall(r’value=”(.*?)”‘, url_initially, re.S)是正则表达语句。
源码 movie
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import re import scrapy from tttest.items import MusicItem, urlItem class Douban250Spider(scrapy.Spider): name = 'douban250' allowed_domains = ['www.oeecc.com'] start_urls = ['http://www.oeecc.com/list/top.html'] def parse(self, response):#获取页码链接 url = "http://www.oeecc.com/list/top.html" yield scrapy.Request(url=url,callback=self.parse_list) def parse_list(self, response):#爬取总页面 li_list = response.xpath('/html/body/div[2]/div[3]/ul/li') urllist=[] for li in li_list: url =li.xpath('a/@href').extract_first() url = 'http://www.oeecc.com' + url urllist.append(url) yield scrapy.Request(url=url,callback = self.parser_info) def parser_info(self, response):#爬取info信息 info = MusicItem() info['title'] = response.xpath('/html/body/div[2]/div[2]/div[1]/div[2]/h1/a/text()').extract_first() url_initially = response.xpath('/html/body/div[2]/div[2]/div[3]/p[2]').extract_first() url_final = re.findall(r'value="(.*?)"', url_initially, re.S) info['url'] = url_final yield info
pipelines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import pymysqlfrom itemadapter import ItemAdapterfrom tttest.items import MusicItemclass TttestPipeline : def __init__ (self ): self.connect = pymysql.connect( host='' , port=3391 , db='' , user='' , passwd='' , charset='utf8' , use_unicode=True , cursorclass=pymysql.cursors.DictCursor ) self.cursor = self.connect.cursor() def process_item (self, item, spider ): if isinstance (item,MusicItem): self.MusicItem(item) return item def MusicItem (self,item ): try : self.cursor.execute(''' SELECT * FROM movie WHERE title=%s ''' ,(item["title" ],)) film = self.cursor.fetchone() if film is None : self.cursor.execute(''' INSERT INTO movie(title,url) VALUE(%s,%s) ''' ,(item['title' ],item['url' ])) else : self.cursor.execute(''' UPDATE movie SET url = %s WHERE title = %s ''' ,(item['url' ],item['title' ])) self.connect.commit() except Exception as err: print ("错误" +str (err))
成果(?) 部分歌曲音频不完整,这是歌曲源的问题。
本来是想把爬下来的音乐全放到这里的,没想到音乐链接每天都会改,隔天就过期。。。总之这个网站不适合练习爬虫,但本帖本意是总结scrapy的用法,也算达到目的了。