赞
踩
1.打开【cmd】
2.进入你要使用的 Anaconda 环境
1.环境名可以在【Pycharm】的【Settings】下【Project:】下找到
2.使用命令:activate 环境名,例如:activate learn
3.进入想要存放 scrapy 项目的目录下
4.新建项目:scrapy startproject xxx项目名,例如:scrapy startproject dem
5.在文件资源管理器打开该目录,就会发现生成了好几个文件
6.使用 Pycharm 打开项目所在目录就可以了。这里我们就把项目创建好了,分析一下自动生成的文件的作用

scrapy shell http://www.sixmh7.com/23370/

我们可以看到,输入命令后,就会有一些日志一样的东西显示出来,蓝色区域则显示出可以使用的scrapy命令,接下来我们需要用到“response”来进行爬取前的分析,你可以接着输入response.body这条命令,看看会输出什么

我们可以发现,章节链接都在<li>里面,这里我们利用scrapy shell来提取一下:
2.2.1.提取章节名
response.xpath('//ul[@id="mh-chapter-list-ol-0"]/li/a/p/text()').extract()

2.2.2.提取章节链接
response.xpath('//ul[@id="mh-chapter-list-ol-0"]/li/a/@href').extract()

这里我们发现,这里并不是全部章节的内容,需要点击查看更多章节动态获取,接下来我们分析动态获取的接口(有一些漫画站不需要动态获取,只是把静态的内容隐藏了)



接下来获取全部的链接和章节名,就不截图了,下面直接上代码
- # 章节链接地址
- urls = response.xpath('//ul[@id="mh-chapter-list-ol-0"]/li/a/@href').extract()
- # 获取所有的章节名
- dir_names = response.xpath('//ul[@id="mh-chapter-list-ol-0"]/li/a/p/text()').extract()
- data = {
- "id": 23370,
- "id2": 1
- }
- response = requests.post("http://www.sixmh7.com/bookchapter/", data=data)
- for index in range(len(response.json())):
- link_url = "/23370/" + response.json()[index]['chapterid'] + ".html"
- urls.append(link_url)
- dir_name = response.json()[index]['chaptername']
- dir_names.append(dir_name)
首先我们要理清楚一个思路:章节链接(link_urls)和图片链接(img_urls)是两种链接,你点进第一章后,利用开发者工具就能发现这一点。相当于说:每页漫画都有两个链接:页面链接和图片来源链接,2.2步中我们利用response.xpath('//ul[@id="mh-chapter-list-ol-0"]/li/a/@href').extract()获取到的是页面链接,而我们要做的就是首先跳转到这个页面,然后找到图片链接,最后将保存的图片链接下载。
2.3.1 接下来我们分析章节里的图片链接,如下图

2.3.2 获取本页的图片链接
这里,我们很容易就和上面一样想到,利response.xpath('//li[@id="page_01"]/img/@src').extract()
来获取图片链接,但是当你真正这么做了,就会发现输出为空。原因就在于这一段html是利用简单的js动态加载进去的,你可以利用response.body来查看html不经过css和js修饰的源码。就会发现并没有打印出图片的信息,只有一堆js

由于这里的动态加载方法较为简单,如下图,可以直接利用开发者工具查看到js代码,因此我们直接获取js,然后进行分析即可(后续复杂的动态请求晚点学)

但是在这里我们发现,这段js代码被加密了,所以我们需要对这段eval代码进行解密
从scrapy shell进去章节页面,输入如下命令获取js
response.xpath('//script/text()').extract()[2].strip()

- eval_js = response.xpath('//script/text()').extract()[2].strip()
- js = """
- function decode(code) {
- if(code.indexOf("eval(function")>-1){
- code = code.replace(/^eval/, '');
- code = eval(code);
- return code;
- }
- }
- """
- com = execjs.compile(js)
- images = com.call('decode', eval_js)[13:].replace(']', '').split(",")
- # 章节链接地址
- urls = response.xpath('//ul[@id="mh-chapter-list-ol-0"]/li/a/@href').extract()
- # 获取所有的章节名
- dir_names = response.xpath('//ul[@id="mh-chapter-list-ol-0"]/li/a/p/text()').extract()
- data = {
- "id": 23370,
- "id2": 1
- }
- response = requests.post("http://www.sixmh7.com/bookchapter/", data=data)
- for index in range(len(response.json())):
- link_url = "/23370/" + response.json()[index]['chapterid'] + ".html"
- urls.append(link_url)
- dir_name = response.json()[index]['chaptername']
- dir_names.append(dir_name))
-
- #进入第一章分析
- scrapy shell http://www.sixmh7.com/23370/1297116.html
- #获取IMG SRC(注意输出的是js,还需要后续处理)
- response.xpath('//script/text()').extract()[2].strip()

1)items.py
- class Sixmh7Item(scrapy.Item):
- # define the fields for your item here like:
- # name = scrapy.Field()
- # 漫画名
- book_name = scrapy.Field()
- # 漫画别名
- nick_name = scrapy.Field()
- # 分类
- tags = scrapy.Field()
- # 作者名字
- author = scrapy.Field()
- # 状态,1代表完结,0代表连载中
- end = scrapy.Field()
- # 封面图远程地址
- cover_url = scrapy.Field()
- # 章节名
- chapter_name = scrapy.Field()
- # 地区id
- area_id = scrapy.Field()
- # 由图片标签组成的字符串
- images = scrapy.Field()
- # 章节序
- chapter_order = scrapy.Field()
- # 漫画简介
- summary = scrapy.Field()
- # 后台配置的api_key
- api_key = scrapy.Field()
- # 用来区别采集源,自己写
- src = scrapy.Field()
- # 用来唯一定义每个漫画,可以是该漫画的url,也可以是该漫画在被采集站的id
- src_url = scrapy.Field()
- # 用来唯一定义每个章节,与src_url同理
- c_src_url = scrapy.Field()
- # 章节链接
- link_url = scrapy.Field()

- BOT_NAME = 'sixmh7'
-
- SPIDER_MODULES = ['sixmh7.spiders']
- NEWSPIDER_MODULE = 'sixmh7.spiders'
- USER_AGENT = 'Mozilla/5.0'
- ROBOTSTXT_OBEY = False
- ITEM_PIPELINES = {
- 'sixmh7.pipelines.Sixmh7Pipeline': 1,
- }
3)sixmh.py(正式版)
- class SixmhSpider(scrapy.Spider):
- name = 'sixmh'
-
- def __init__(self):
- # 章节链接server域名
- self.server_link = 'http://www.sixmh7.com'
- self.allowed_domains = ['www.sixmh7.com']
- self.start_urls = ['http://www.sixmh7.com/23370/']
-
- # 可以查看scrapy文档
- def start_requests(self):
- yield scrapy.Request(url=self.start_urls[0], callback=self.parse1)
-
- # 解析response,获取每个大章节图片链接地址
- def parse1(self, response):
- items = []
- # 漫画名
- book_name = response.xpath('//div[@class="cy_title"]/h1/text()').extract()[0]
- # 漫画别名
- nick_name = response.xpath('//div[@class="cy_title"]/h1/text()').extract()[0]
- # 分类
- tags = response.xpath('//div[@class="cy_xinxi"]/span/text()').extract()[3].replace("标签:", "")
- # 作者名字
- author = response.xpath('//div[@class="cy_xinxi"]/span/text()').extract()[0].replace("作者:", "")
- # 状态,1代表完结,0代表连载中
- status = response.xpath('//div[@class="cy_xinxi"]/span/font/text()').extract()[0]
- if '连载中' == status:
- end = 0
- else:
- end = 1
- # 封面图远程地址
- cover_url = response.xpath('//div[@class="cy_info_cover"]/img/@src').extract()[0]
- # 漫画简介
- summary = response.xpath('//div[@class="cy_xinxi cy_desc"]/p/text()').extract()[0]
- # 章节链接地址
- urls = response.xpath('//ul[@id="mh-chapter-list-ol-0"]/li/a/@href').extract()
- # 获取所有的章节名
- dir_names = response.xpath('//ul[@id="mh-chapter-list-ol-0"]/li/a/p/text()').extract()
- data = {
- "id": 23370,
- "id2": 1
- }
- response = requests.post("http://www.sixmh7.com/bookchapter/", data=data)
- for index in range(len(response.json())):
- link_url = "/23370/" + response.json()[index]['chapterid'] + ".html"
- urls.append(link_url)
- dir_name = response.json()[index]['chaptername']
- dir_names.append(dir_name)
- # 保存章节链接和章节名
- for index in range(len(urls)):
- item = Sixmh7Item()
- item['api_key'] = 'abc123456'
- item['link_url'] = self.server_link + urls[index]
- item['chapter_name'] = dir_names[index]
- item['chapter_order'] = re.sub('\D', '', dir_names[index])
- item['book_name'] = book_name
- item['nick_name'] = nick_name
- item['tags'] = tags
- item['author'] = author
- item['end'] = end
- item['cover_url'] = cover_url
- item['summary'] = summary
- item['src'] = self.server_link
- item['src_url'] = self.start_urls[0]
- item['c_src_url'] = self.server_link + urls[index]
- item['area_id'] = 1
- items.append(item)
- # 根据每个章节的连接,发送request请求,并传递item参数
- for item in items:
- yield scrapy.Request(url=item['link_url'], meta={'item': item}, callback=self.parse2)
-
- # 解析一个章节的第一页的页码数和图片链接
- def parse2(self, response):
- # 接收传递的item
- item = response.meta['item']
- # 下面一句不能少,是用来更新要解析的章节链接
- item['link_url'] = response.url
- hxs = Selector(response)
- # 获取章节第一页图片的链接
- eval_js = hxs.xpath('//script/text()').extract()[2].strip()
- js = """
- function decode(code) {
- if(code.indexOf("eval(function")>-1){
- code = code.replace(/^eval/, '');
- code = eval(code);
- return code;
- }
- }
- """
- com = execjs.compile(js)
- images = com.call('decode', eval_js)[13:].replace(']', '').split(",")
- tags = []
- for i in images:
- tags.append(eval(i))
- # 将获取的章节的第一页的图片链接保存到img_url中
- item['images'] = ','.join(tags)
- # 返回item,交给item pipeline下载图片
- yield item

这一段代码比较多,但是我相信只要你一步步敲过来,那么肯定很容易理解代码,而且我在学习原博客的过程中,也是遇到了许多坑,修改了很多地方,如果你直接复制我的代码却没法运行,你可以这么做:将报错以后的地方全部注释,然后print输出报错的东西(比如item报错你就print(item)一下),然后对照报错信息进行修改。
- import requests
-
-
- class Sixmh7Pipeline:
- def process_item(self, item, spider):
- url = 'http://www.xswang.online/api.php/postbot/save'
- print(item)
- res = requests.post(url=url, data=item)
5)运行
scrapy crawl sixmh
复杂的动态加载如何实现爬取
遇到需要登录,甚至需要vip的内容如何爬取
这些就留着接下来一段时间学习了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。