Scrapy框架学习
文章目录
1.基础
1.安装
pip install scrapy
2. 常见的命令
scrapy startproject: 创建新的爬虫项目。
scrapy genspider: 创建新的爬虫。
scrapy crawl: 运行爬虫。
scrapy shell: 启动 Scrapy shell,可以在交互式命令行中测试爬虫代码。
scrapy view: 打开给定 URL 的页面,方便调试。
scrapy fetch: 使用 Scrapy 的下载器下载给定 URL 的页面。
#配置日志打印级别 settings.py
L0G_LEVEL='ERROR' #当有报错ERROR了会执行打印
或者用以下命令启动
scrapy crawl dzx -s LOG_LEVEL=ERROR
pipelines.py——>管道,保存数据
settings.py——>设置文件,UA,启动管道
spiders
——>自己定义的spider的文件夹
3、配置settings文件
-
ROBOTSTXT_OBEY = False
robots是一种反爬协议。在协议中规定了哪些身份的爬虫无法爬取的资源有哪些。
在配置文件中setting,取消robots的监测:
-
在配置文件中配置全局的UA:USER_AGENT=‘xxxx’
-
在配置文件中加入日志等级:LOG_LEVEL = ‘ERROR’ 只输出错误信息
其它日志级别
- CRITICAL 严重错误
- ERROR 错误
- WARNING 警告
- INFO 消息
- DEBUG 调试
2.开始
1.创建第一个项目
首先在目标文件夹下打开cmd或者终端
scrapy startproject duanzhi(项目名字自定义)
cd duanzhi
scrapy genspider dzx duanzixing.com
设置一下输出日志 当有报错ERROR了会执行打印
写一部分代码来观察
class DzxSpider(scrapy.Spider):
name = "dzx"
# allowed_domains = ["duanzixing.com"]
start_urls = ["https://duanzixing.com"]
def parse(self, response, **kwargs):
print(response)
# 获取响应的内容
# print(response.text)
# 当前响应的url
print('response.url:', response.url)
# 当前响应对应的请求的url
print('response.request.url:', response.request.url)
# 响应头
print('response.headers:', response.headers)
# 响应的请求头
print('response.request.headers:', response.request.headers)
# 响应体
print('response.body:', response.body)
# 返回响应的内容
print('response.text:', response.text)
# 响应的状态码
print('response.status:', response.status)
# 获取响应的json数据 如果响应的内容不是json格式的数据,会报错
# print('response.json():', response.json())
1.观察网页
可以得到
标题
和正文
2.用以前的方式进行获取
import requests
from lxml import etree
url = "https://duanzixing.com/"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36',
}
res = requests.get(url, headers=headers)
html = etree.HTML(res.text)
# 获取所有的段子
excerpt_list = html.xpath('/html/body/section/div/div/article')
# print(len(excerpt_list))
for tree in excerpt_list:
title = tree.xpath('./header/h2/a/text()')
text = tree.xpath('./p[@class="note"]/text()')
print(title)
print(text)
3.用scrapy
def parse(self, response, **kwargs):
excerpt_list=response.xpath('/html/body/section/div/div/article')
data={}
for tree in excerpt_list:
title = tree.xpath('./header/h2/a/text()').extract()
text = tree.xpath('./p[@class="note"]/text()').extract()
print(title)
print(text)
3.了解scrapyShell
https://duanzixing.com
4.settings.py中的设置信息
3.1 为什么项目中需要配置文件
在配置文件中存放一些公共变量,在后续的项目中方便修改,如:本地测试数据库和部署服务器的数据库不一致
3.2 配置文件中的变量使用方法
- 变量名一般全部大写
- 导入即可使用
3.3 settings.py中的重点字段和含义
-
USER_AGENT 设置ua
-
ROBOTSTXT_OBEY 是否遵守robots协议,默认是遵守
-
CONCURRENT_REQUESTS 设置并发请求的数量,默认是16个
-
DOWNLOAD_DELAY 下载延迟,默认无延迟 (下载器在从同一网站下载连续页面之前应等待的时间(以秒为单位)。这可以用来限制爬行速度,以避免对服务器造成太大影响)
-
COOKIES_ENABLED 是否开启cookie,即每次请求带上前一次的cookie,默认是开启的
-
DEFAULT_REQUEST_HEADERS 设置默认请求头,这里加入了USER_AGENT将不起作用
-
SPIDER_MIDDLEWARES 爬虫中间件,设置过程和管道相同
-
DOWNLOADER_MIDDLEWARES 下载中间件
-
LOG_LEVEL 控制终端输出信息的log级别,终端默认显示的是debug级别的log信息
- LOG_LEVEL = “WARNING”
- CRITICAL 严重
- ERROR 错误
- WARNING 警告
- INFO 消息
- DEBUG 调试
- LOG_LEVEL = “WARNING”
-
LOG_FILE 设置log日志文件的保存路径,如果设置该参数,终端将不再显示信息
LOG_FILE = “./test.log”
-
其他设置参考:https://www.jianshu.com/p/df9c0d1e9087
5.pipeline管道的深入使用
1.代码配置
class ITSpider(scrapy.Spider):
name = 'ITSpider'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://duanzixing.com/page/1/']
# 通过终端写入文件的方式
def parse(self, response):
article_list = response.xpath('/html/body/section/div/div/article')
# 创建列表, 存储数据
all_data = []
for article in article_list:
title = article.xpath('./header/h2/a/text()').extract_first()
con = article.xpath('./p[2]/text()').extract_first()
dic = {
'title': title,
'con': con
}
all_data.append(dic)
return all_data
-
终端命令
scrapy crawl 爬虫名称-o 文件名.csv
scrapy crawl ITSpider -o ITSpider.csv
将文件存储到ITSpider.csv 文件中
2.开启管道
pipeline中常用的方法:
- process_item(self,item,spider):实现对item数据的处理
- open_spider(self, spider): 在爬虫开启的时候仅执行一次
- close_spider(self, spider): 在爬虫关闭的时候仅执行一次
3.进行管道测试 pipelines.py
class DuanzhiPipeline:
# 在爬虫开启的时候仅执行一次
def open_spider(self, item):
print("爬虫开始了")
# 进行文件的打开
self.f = open('duanzhi.txt', 'w', encoding='utf-8')
# 实现对item数据的处理
def process_item(self, item, spider):
self.f.write(item['title'] + '\n')
self.f.write(item['text'] + '\n')
return item
# 在爬虫关闭的时候仅执行一次
def close_spider(self, item):
print("爬虫结束了")
self.f.close()
4.总结代码
1.dzx.py
def parse(self, response, **kwargs):
item = DuanzhiItem()
excerpt_list = response.xpath('/html/body/section/div/div/article')
for tree in excerpt_list:
title = tree.xpath('./header/h2/a/text()').extract()
text = tree.xpath('./p[@class="note"]/text()').extract()
item['title'] = title
item['text'] = text
yield item
2.items.py
class DuanzhiItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
text = scrapy.Field()
3.pipelines.py
class DuanzhiPipeline:
# 在爬虫开启的时候仅执行一次
def open_spider(self, item):
print("爬虫开始了")
# 进行文件的打开
self.f = open('duanzhi.txt', 'w', encoding='utf-8')
# 实现对item数据的处理
def process_item(self, item, spider):
if item['title'] and item['text']:
self.f.write(item['title'][0] + '\n')
self.f.write(item['text'][0] + '\n')
return item
# 在爬虫关闭的时候仅执行一次
def close_spider(self, item):
print("爬虫结束了")
self.f.close()
4.运行并产生duanzhi.txt
没有文件产生别文件settings.py 打开管道
5.动态数据实操(新发地)
看网页分析
可以得知是post 请求 且数据为json且存储在list下面
我们只需获取以下数据:
prodName: “大白菜”
avgPrice: “0.53”
unitInfo: “斤”
pubDate: “2023-09-19 00:00:00”
实战开始:
1.创建爬虫
scrapy startproject xingfadi
cd xingdadi
scrapy genspider xfd xinfadi.com.cn
2.setting.py
设置日志
LOG_LEVEL = "WARNING"
设置robots
ROBOTSTXT_OBEY =False
打开管道
ITEM_PIPELINES = {
"xingfadi.pipelines.XingfadiPipeline": 300,
}
3.xfd.py
import scrapy
from xingfadi.items import XingfadiItem
class XfdSpider(scrapy.Spider):
name = "xfd"
# allowed_domains = ["xinfadi.com.cn"]
start_urls = ["http://www.xinfadi.com.cn/getPriceData.html"]
def parse(self, response):
item = XingfadiItem()
html = response.json()
all_list = html["list"]
for i in all_list:
prodName = i["prodName"]
avgPrice = i["avgPrice"]
unitInfo = i["unitInfo"]
pubDate = i["pubDate"]
item["prodName"] = prodName
item["avgPrice"] = avgPrice
item["unitInfo"] = unitInfo
item["pubDate"] = pubDate
yield item
4.items.py
import scrapy
class XingfadiItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
prodName = scrapy.Field()
avgPrice = scrapy.Field()
unitInfo = scrapy.Field()
pubDate = scrapy.Field()
5.pipelines.py
class XingfadiPipeline:
def open_spider(self, spider):
print("爬虫开始了")
self.f = open("新发地价格.txt", "w", encoding="utf-8")
def process_item(self, item, spider):
if item["prodName"] and item["avgPrice"] and item["unitInfo"] and item["pubDate"]:
self.f.write(
item["prodName"] + ": " + item["avgPrice"] + item["unitInfo"] + " 时间:" + item["pubDate"] + "\n")
return item
def close_spider(self, spider):
print("爬虫结束了")
self.f.close()
6.出结果
6.总结
1.创建好项目以后先要配置setting里面的内容
2.无论是post还是get请求都可以直接写
3.以前需要导入的包已经自动导入不需要再次导入
4.items.py 的属性要和 爬虫.py 里面的属性一一对应否则会报错
5.pipelines.pt 一定要
if
在进行写入否则不会成功 我也不知道为什么😄乱写👌
5.scrapy存数据库
1.MYSQL
1.数据库建表
create database spider;
use spider;
CREATE TABLE dzx (
title VARCHAR(255),
text TEXT
);
2.pipelines.py
基于第一个案例的dzx来说进行一个把数据存储到数据库中
import pymysql
class DuanzhiPipeline:
def open_spider(self, spider):
# 在爬虫开启的时候仅执行一次
print("爬虫开始了")
self.db = pymysql.connect(host='localhost', user='root', password='1234',
port=3306, db='spider', charset='utf8')
self.cursor = self.db.cursor()
def process_item(self, item, spider):
# 实现对item数据的处理
try:
title = item['title']
text = item['text']
# 构建SQL语句
sql = "INSERT INTO dzx (title, text) VALUES (%s, %s)"
# 执行SQL语句,并传递参数
self.cursor.execute(sql, (title, text))
# 提交事务
self.db.commit()
except Exception as e:
# 处理数据库出错的情况
print("数据库出错:" + str(e))
# 回滚事务
self.db.rollback()
return item
def close_spider(self, spider):
# 在爬虫关闭的时候仅执行一次
print("爬虫结束了")
self.cursor.close()
self.db.close()
3.运行查看结果
4.总结
sql
语句要正确 尤其是对添加内容的时候
2.MongoDB
pipelines.py
用上面的新发地的案例进行修改
from pymongo import MongoClient
class XingfadiPipeline:
def open_spider(self, spider):
print("爬虫开始了")
# 连接数据库
self.con = MongoClient(host='127.0.0.1', port=27017)
# 创建库
self.db = self.con['spider']
# 创建集合
self.myset = self.db['xfd']
def process_item(self, item, spider):
# 把item转换成字典
result = self.myset.insert_one(dict(item))
print(result.inserted_id)
return item
def close_spider(self, spider):
print("爬虫结束了")
self.con.close()
对于MongoDB来说 无需提前进行对数据库的创建
但有必要进行一次测试连接
from pymongo import MongoClient
# 连接数据库
client = MongoClient(host='127.0.0.1', port=27017)
# 测试连接
try:
client.admin.command('ping')
print("成功连接到MongoDB!")
except Exception as e:
print("连接失败:", e)
# 关闭连接
client.close()
运行不报错有没看见数据?
对于pycharm来说 刷新看一下或者打开勾选选择数据库
6.scrapy下载图片
1.settings 设置
ITEM_PIPELINES = {
"desk.pipelines.DeskPipeline": 300,
"desk.pipelines.ImgPipeline": 400, # 图片下载
}
IMAGES_STORE = "./img" # 图片存储路径
1.要打开对应的下载图片的管道
2.要设置一个下载图片的存储地址
2.通用下载图片配置文件
import scrapy
from urllib.parse import urljoin
class ImgSpider(scrapy.Spider):
name = 'img'
# allowed_domains = ['desk.zol.com.cn/dongman']
start_urls = ['http://desk.zol.com.cn/dongman/']
def parse(self, resp, **kwargs):
# 先抓取到每个图片详情的url
url_list = resp.xpath('//ul[@class="pic-list2 clearfix"]/li/a/@href').extract()
# 获取到url列表后 进行循环进行每一个url详情页的请求
for url in url_list:
# 因为抓取到的url并不完整,需要进行手动拼接
# urljoin('https://desk.zol.com.cn/dongman/', '/bizhi/8301_103027_2.html')
url = urljoin('https://desk.zol.com.cn/dongman/', url)
# 拼凑完发现当前url中有下载exe的url,将其去除
if url.find('exe') != -1:
continue
yield scrapy.Request(url, callback=self.parse_detail)
# 对详情页进行解析
def parse_detail(self, resp):
# 获取当前详情页中最大尺寸图片的url
max_img_url = resp.xpath('//dd[@id="tagfbl"]/a/@href').extract()
# 判断当前最大图片的url地址,为倒数第二个,如果当前图片列表url长度小于2 则当前证明不是图片的url
if len(max_img_url) > 2:
max_img_url = urljoin('https://desk.zol.com.cn/', max_img_url[0])
# 对url页面进行请求 获取最终大图的页面
yield scrapy.Request(max_img_url, callback=self.parse_img_detail)
def parse_img_detail(self, resp):
# 解析出大图的url
img_src = resp.xpath("//img[1]/@src").extract_first()
return {'img_src': img_src}
img_src
是固定的名称 或者可以自定义修改 ,要pipelines.py和img.py 传递的参数要一一对应
3.pipelines.py
from itemadapter import ItemAdapter
from scrapy.pipelines.images import ImagesPipeline
import scrapy
class DeskPipeline:
def process_item(self, item, spider):
return item
class Imgspipline(ImagesPipeline):
# 1. 发送请求(下载图片, 文件, 视频,xxx)
def get_media_requests(self, item, info):
# 获取到图片的url
url = item['img_src']
# 进行请求
yield scrapy.Request(url=url, meta={"url": url}) # 直接返回一个请求对象即可
# 2. 图片存储路径
def file_path(self, request, response=None, info=None, *, item=None):
# 当前获取请求的url的方式有2种
# 获取到当前的url 用于处理下载图片的名称
file_name = item['img_src'].split("/")[-1] # 用item拿到url
# file_name = request.meta['url'].split("/")[-1] # 用meta传参获取
return file_name
# 3. 可能需要对item进行更新
def item_completed(self, results, item, info):
# print('results', results)
for r in results:
# 获取每个图片的路径
print(r[1]['path'])
return item # 一定要return item 把数据传递给下一个管道
4.img.py
import scrapy
from urllib.parse import urljoin
class ImgSpider(scrapy.Spider):
name = 'img'
# allowed_domains = ['desk.zol.com.cn/dongman']
start_urls = ['http://desk.zol.com.cn/dongman/']
def parse(self, resp, **kwargs):
# 先抓取到每个图片详情的url
url_list = resp.xpath('//ul[@class="pic-list2 clearfix"]/li/a/@href').extract()
# 获取到url列表后 进行循环进行每一个url详情页的请求
for url in url_list:
# 因为抓取到的url并不完整,需要进行手动拼接
# urljoin('https://desk.zol.com.cn/dongman/', '/bizhi/8301_103027_2.html')
url = urljoin('https://desk.zol.com.cn/dongman/', url)
# 拼凑完发现当前url中有下载exe的url,将其去除
if url.find('exe') != -1:
continue
yield scrapy.Request(url, callback=self.parse_detail)
# 对详情页进行解析
def parse_detail(self, resp):
# 获取当前详情页中最大尺寸图片的url
max_img_url = resp.xpath('//dd[@id="tagfbl"]/a/@href').extract()
# 判断当前最大图片的url地址,为倒数第二个,如果当前图片列表url长度小于2 则当前证明不是图片的url
if len(max_img_url) > 2:
max_img_url = urljoin('https://desk.zol.com.cn/', max_img_url[0])
# 对url页面进行请求 获取最终大图的页面
yield scrapy.Request(max_img_url, callback=self.parse_img_detail)
def parse_img_detail(self, resp):
# 解析出大图的url
img_src = resp.xpath("//img[1]/@src").extract_first()
return {'img_src': img_src}
5.总结
1.对应最后的传参一点要对应好相对的
元素
2.记得要设置好存储图片的路径以及打开对应的管道
3.报错多问G哥
7.scrapy模拟登陆&分页
1.回顾之前的模拟登陆的方法
1 requests模块模拟登陆?
- 直接携带cookies请求页面
- 找url地址,发送post请求存储cookie
2 selenium模拟登陆?
- 找到对应的input标签,输入文本点击登陆
3 scrapy模拟登陆
- 直接携带cookies
- 找url地址,发送post请求存储cookie
- 找到对应的form表单,自动解析input标签,自动解析post请求的url地址,自动带上数据,自动发送请求
2.scrapy携带cookies直接获取需要登陆后的页面
17k小说网
https://user.17k.com/
2.1 应用场景
- cookie过期时间很长,常见于一些不规范的网站
- 能在cookie过期之前把搜有的数据拿到
- 配合其他程序使用,比如其使用selenium把登陆之后的cookie获取到保存到本地,scrapy发送请求之前先读取本地cookie
2.2 通过修改settings中DEFAULT_REQUEST_HEADERS携带cookie
settings.py
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
'Cookie': 'ASP.NET_SessionId=n4lwamv5eohaqcorfi3dvzcv; xiaohua_visitfunny=103174; xiaohua_web_userid=120326; xiaohua_web_userkey=r2sYazfFMt/rxUn8LJDmUYetwR2qsFCHIaNt7+Zpsscpp1p6zicW4w=='
}
注意:需要打开COOKIES_ENABLED,否则上面设定的cookie将不起作用
# Disable cookies (enabled by default)
COOKIES_ENABLED = False
xiaoshuo.py
import scrapy
class DengluSpider(scrapy.Spider):
name = 'denglu'
allowed_domains = ['17k.com']
start_urls = ['https://user.17k.com/ck/user/mine/readList?page=1&appKey=2406394919']
def parse(self, res):
print(res.text)
局限性:
当前设定方式虽然可以实现携带cookie保持登录,但是无法获取到新cookie,也就是当前cookie一直是固定的
如果cookie是经常性变化,那么当前不适用
2.3 实现:重构scrapy的starte_rquests方法
scrapy中start_url是通过start_requests来进行处理的,其实现代码如下
def start_requests(self):
cls = self.__class__
if method_is_overridden(cls, Spider, 'make_requests_from_url'):
warnings.warn(
"Spider.make_requests_from_url method is deprecated; it "
"won't be called in future Scrapy releases. Please "
"override Spider.start_requests method instead (see %s.%s)." % (
cls.__module__, cls.__name__
),
)
for url in self.start_urls:
yield self.make_requests_from_url(url)
else:
for url in self.start_urls:
yield Request(url, dont_filter=True)
所以对应的,如果start_url地址中的url是需要登录后才能访问的url地址,则需要重写start_request方法并在其中手动添加上cookie
settings.py
import scrapy
class DengluSpider(scrapy.Spider):
name = 'denglu'
# allowed_domains = ['https://user.17k.com/ck/user/mine/readList?page=1']
start_urls = ['https://user.17k.com/ck/user/mine/readList?page=1&appKey=2406394919']
def start_requests(self):
cookies = 'GUID=796e4a09-ba11-4ecb-9cf6-aad19169267d; Hm_lvt_9793f42b498361373512340937deb2a0=1660545196; c_channel=0; c_csc=web; accessToken=avatarUrl%3Dhttps%253A%252F%252Fcdn.static.17k.com%252Fuser%252Favatar%252F18%252F98%252F90%252F96139098.jpg-88x88%253Fv%253D1650527904000%26id%3D96139098%26nickname%3D%25E4%25B9%25A6%25E5%258F%258BqYx51ZhI1%26e%3D1677033668%26s%3D8e116a403df502ab; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2296139098%22%2C%22%24device_id%22%3A%22181d13acb2c3bd-011f19b55b75a8-1c525635-1296000-181d13acb2d5fb%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%2C%22first_id%22%3A%22796e4a09-ba11-4ecb-9cf6-aad19169267d%22%7D; Hm_lpvt_9793f42b498361373512340937deb2a0=1661483362'
cookie_dic = {}
for i in cookies.split(';'):
v = i.split('=')
cookie_dic[v[0]] = v[1]
# {i.split('=')[0]:i.split('=')[1] for i in cookies_str.split('; ')} # 简写
for url in self.start_urls:
yield scrapy.Request(url, cookies=cookie_dic)
def parse(self, response):
print(response.text)
注意:
- scrapy中cookie不能够放在headers中,在构造请求的时候有专门的cookies参数,能够接受字典形式的coookie
- 在setting中设置ROBOTS协议、USER_AGENT
3.scrapy.FormRequest发送post请求
我们知道可以通过scrapy.Request()指定method、body参数来发送post请求;那么也可以使用scrapy.FormRequest()来发送post请求
1 scrapy.FormRequest()的使用
通过scrapy.FormRequest能够发送post请求,同时需要添加fromdata参数作为请求体,以及callback
login_url = 'https://passport.17k.com/ck/user/login'
yield scrapy.FormRequest(
url=login_url,
formdata={'loginName': '17346570232', 'password': 'xlg17346570232'},
callback=self.do_login
)
2 使用scrapy.FormRequest()登陆
1 思路分析
- 找到post的url地址:点击登录按钮进行抓包,然后定位url地址为https://www.xiaohua.com/Handler/Login.ashx
- 找到请求体的规律:分析post请求的请求体,其中包含的参数均在前一次的响应中
- 否登录成功:通过请求个人主页,观察是否包含用户名
2 代码实现如下:
import scrapy
class DlSpider(scrapy.Spider):
name = "dl"
allowed_domains = ["17k.com"]
start_urls = ["https://user.17k.com/ck/user/myInfo/96139098?appKey=2406394919"]
# 在请求start_urLs之前先登陆登陆以后就有了登录后的cookie此刻cookie是自动抓取的
def start_requests(self):
# 先在要在这里处理登陆的功能因为scrapy一执行自动调用当前方法
# for url in self.start_urls:
# yield scrapy.Request(url=url)
login_url = 'https://passport.17k.com/ck/user/login'
# yield scrapy.Request(login_url, method='POST',
# body='loginName=17346570232&password=xlg17346570232',
# callback=self.do_start_requests)
# FormRequest 是Scrapy发送POST请求的方法
yield scrapy.FormRequest(login_url,
formdata={
'loginName': '17346570232',
'password': 'xlg17346570232'
},
callback=self.do_start_requests)
# 登录成功后再去请求start_urls
def do_start_requests(self, response, **kwargs):
for url in self.start_urls:
yield scrapy.Request(url=url)
def parse(self, response, **kwargs):
print(response.text)
4.分页
1.分析
通过爬取段子页面的信息,学习如何实现翻页请求
地址:https://duanzixing.com/
思路分析:
- 获取首页的数据
- 寻找下一页的地址,进行翻页,获取数据
注意:
-
可以在settings中设置ROBOTS协议
# False表示忽略网站的robots.txt协议,默认为True ROBOTSTXT_OBEY = False
-
可以在settings中设置User-Agent:
# scrapy发送的每一个请求的默认UA都是设置的这个User-Agent USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
2.代码实现
import scrapy
class DzSpider(scrapy.Spider):
name = "dz"
allowed_domains = ["duanzixing.com"]
start_urls = ["https://duanzixing.com/"]
def parse(self, response, **kwargs):
url = 'https://duanzixing.com/page/%d/'
for i in range(1, 11):
new_url = url % i
# print(new_url)
yield scrapy.Request(new_url, callback=self.parse_page, meta={
'url': new_url})
def parse_page(self, response, **kwargs):
url = response.meta['url']
article_list = response.xpath('//article[@class="excerpt"]')
for article in article_list:
data = {}
title = article.xpath('./header/h2/a/text()').extract_first()
con = article.xpath('./p[@class="note"]/text()').extract_first()
data['title'] = title
data['con'] = con
print(data, url)
yield data
5.参数解释
1.上诉代码:
- 中括号中的参数为可选参数
- callback:表示当前的url的响应交给哪个函数去处理
- meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
- dont_filter:默认为False,会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
- method:指定POST或GET请求
- headers:接收一个字典,其中不包括cookies
- cookies:接收一个字典,专门放置cookies
- body:接收一个字典,为POST的数据
2.meta参数的使用
meta的形式:字典
meta的作用:meta可以实现数据在不同的解析函数中的传递
在爬虫文件的parse方法中,提取详情页增加之前callback指定的parse_detail函数:
def parse(self,response):
...
yield scrapy.Request(detail_url, callback=self.parse_detail,meta={"item":item})
...
def parse_detail(self,response):
#获取之前传入的item
item = resposne.meta["item"]
特别注意
- meta参数是一个字典
- meta字典中有一个固定的键
proxy