用for或while循环来处理不确定页数的网页数据爬取
- 欢迎使用Markdown编辑器
- ajax 请求url
- 解析网页内容
- 写入MongoDB
- 实例化数据提取类
- 添加循环判断,如果content 为空表示此页已经下载完成了,break 跳出循环
- break
- response 是json,json内容是html,html 为文本不能直接使用.css 提取,要先转换
- while循环构造url递归爬下一页
欢迎使用Markdown编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1 功能;
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC
语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本需要学习的地方
有两种方法。
第一种方式 使用 For 循环配合 break 语句,尾页的页数设置一个较大的参数,足够循环爬完所有页面,爬取完成时,break 跳出循环,结束爬取。
第二种方法 使用 While 循环,可以结合 break 语句,也可以设起始循环判断条件为 True,从头开始循环爬取直到爬完最后一页,然后更改判断条件为 False 跳出循环,结束爬取。
Requests 和 Scrapy 中分别用 For 循环和 While 循环爬取不确定页数的网页。
摘要:Requests 和 Scrapy 中分别用 For 循环和 While 循环爬取不确定页数的网页。
我们通常遇到的网站页数展现形式有这么几种:
第一种是直观地显示所有页数,比如此前爬过的酷安、东方财富网,
文章见:
∞ Scrapy 爬取并分析酷安 6000 款 App,找到良心佳软
∞ 50 行代码爬取东方财富网百万行财务报表数据
第二种是不直观显示网页总页数,需要在后台才可以查看到,比如之前爬过的虎嗅网,文章见:
∞ pyspider 爬取并分析虎嗅网 5 万篇文章
第三种是今天要说的,不知道具体有多少页的网页,比如豌豆荚:
对于,前两种形式的网页,爬取方法非常简单,使用 For 循环从首页爬到尾页就行了,第三种形式则不适用,因为不知道尾页的页数,所以循环到哪一页结束无法判断。
那如何解决呢?有两种方法。
第一种方式 使用 For 循环配合 break 语句,尾页的页数设置一个较大的参数,足够循环爬完所有页面,爬取完成时,break 跳出循环,结束爬取。
第二种方法 使用 While 循环,可以结合 break 语句,也可以设起始循环判断条件为 True,从头开始循环爬取直到爬完最后一页,然后更改判断条件为 False 跳出循环,结束爬取。
实际案例
下面,我们以 豌豆荚 网站中「视频」类别下的 App 信息为例,使用上面两种方法抓取该分类下的所有 App 信息,包括 App 名称、评论、安装数量和体积。
首先,简要分析下网站,可以看到页面是通过 Ajax 加载的,GET 请求附带一些参数,可以使用 params 参数构造 URL 请求,但不知道一共有多少页,为了确保下载完所有页,设置较大的页数,比如 100页 甚至 1000 页都行。
下面我们尝试使用 For 和 While 循环爬取 。
Requests
▌For 循环
主要代码如下:
class Get_page():
def init(self):
ajax 请求url
self.ajax_url = ‘https://www.wandoujia.com/wdjweb/api/category/more’
def get_page(self,page,cate_code,child_cate_code):
params = {
‘catId’: cate_code,
‘subCatId’: child_cate_code,
‘page’: page,
}
response = requests.get(self.ajax_url, headers=headers, params=params)
content = response.json()[‘data’][‘content’] #提取json中的html页面数据
return content
def parse_page(self, content):
解析网页内容
contents = pq(content)(’.card’).items()
data = []
for content in contents:
data1 = {
‘app_name’: content(’.name’).text(),
‘install’: content(’.install-count’).text(),
‘volume’: content(’.meta span:last-child’).text(),
‘comment’: content(’.comment’).text(),
}
data.append(data1)
if data:
写入MongoDB
self.write_to_mongodb(data)
if name == ‘main’:
实例化数据提取类
wandou_page = Get_page()
cate_code = 5029 # 影音播放大类别编号
child_cate_code = 716 # 视频小类别编号
for page in range(2, 100):
print(’*’ * 50)
print(‘正在爬取:第 %s 页’ % page)
content = wandou_page.get_page(page,cate_code,child_cate_code)
添加循环判断,如果content 为空表示此页已经下载完成了,break 跳出循环
if not content == ‘’:
wandou_page.parse_page(content)
sleep = np.random.randint(3,6)
time.sleep(sleep)
else:
print(‘该类别已下载完最后一页’)
break
这里,首先创建了一个 Get_page 类,get_page 方法用于获取 Response 返回的 json 数据,通过 json.cn 网站解析 json 解析后发现需要提取的内容是一段包裹在 data 字段下 content 键中的 html 文本,可以使用 parse_page 方法中的 pyquery 函数进行解析,最后提取出 App 名称、评论、安装数量和体积四项信息,完成抓取。
在主函数中,使用了 if 函数进行条件判断,若 content 不为空,表示该页有内容,则循环爬下去,若为空则表示此页面已完成了爬取,执行 else 分支下的 break 语句结束循环,完成爬取。
爬取结果如下,可以看到该分类下一共完成了全部 41 页的信息抓取。
▌While 循环
While 循环和 For 循环思路大致相同,不过有两种写法,一种仍然是结合 break 语句,一种则是更改判断条件。
总体代码不变,只需修改 For 循环部分:
page = 2 # 设置爬取起始页数
while True:
print(’*’ * 50)
print(‘正在爬取:第 %s 页’ %page)
content = wandou_page.get_page(page,cate_code,child_cate_code)
if not content == ‘’:
wandou_page.parse_page(content)
page += 1
sleep = np.random.randint(3,6)
time.sleep(sleep)
else:
print(‘该类别已下载完最后一页’)
break
或者:
page = 2 # 设置爬取起始页数
page_last = False # while 循环初始条件
while not page_last:
#…
else:
break
page_last = True # 更改page_last 为 True 跳出循环
结果如下,可以看到和 For 循环的结果是一样的。
我们可以再测试一下其他类别下的网页,比如选择「K歌」类别,编码为:718,然后只需要对应修改主函数中的child_cate_code 即可,再次运行程序,可以看到该类别下一共爬取了 32 页。
由于 Scrapy 中的写法和 Requests 稍有不同,所以接下来,我们在 Scrapy 中再次实现两种循环的爬取方式 。
Scrapy
▌For 循环
Scrapy 中使用 For 循环递归爬取的思路非常简单,即先批量生成所有请求的 URL,包括最后无效的 URL,后续在 parse 方法中添加 if 判断过滤无效请求,然后爬取所有页面。由于 Scrapy 依赖于Twisted框架,采用的是异步请求处理方式,也就是说 Scrapy 边发送请求边解析内容,所以这会发送很多无用请求。
def start_requests(self):
pages=[]
for i in range(1,10):
url=‘http://www.example.com/?page=%s’%i
page = scrapy.Request(url,callback==self.pare)
pages.append(page)
return pages
下面,我们选取豌豆荚「新闻阅读」分类下的「电子书」类 App 页面信息,使用 For 循环尝试爬取,主要代码如下:
def start_requests(self):
cate_code = 5019 # 新闻阅读
child_cate_code = 940 # 电子书
print(’*’ * 50)
pages = []
for page in range(2,50):
print('正在爬取:第 %s 页 ’ %page)
params = {
‘catId’: cate_code,
‘subCatId’: child_cate_code,
‘page’: page,
}
category_url = self.ajax_url + urlencode(params)
pa = yield scrapy.Request(category_url,callback=self.parse)
pages.append(pa)
return pages
def parse(self, response):
if len(response.body) >= 100: # 判断该页是否爬完,数值定为100是因为response无内容时的长度是87
jsonresponse = json.loads(response.body_as_unicode())
contents = jsonresponse[‘data’][‘content’]
response 是json,json内容是html,html 为文本不能直接使用.css 提取,要先转换
contents = scrapy.Selector(text=contents, type=“html”)
contents = contents.css(’.card’)
for content in contents:
item = WandoujiaItem()
item[‘app_name’] = content.css(’.name::text’).extract_first()
item[‘install’] = content.css(’.install-count::text’).extract_first()
item[‘volume’] = content.css(’.meta span:last-child::text’).extract_first()
item[‘comment’] = content.css(’.comment::text’).extract_first().strip()
yield item
上面代码很好理解,简要说明几点:
第一、判断当前页是否爬取完成的判断条件改为了 response.body 的长度大于 100。
因为请求已爬取完成的页面,返回的 Response 结果是不为空的,而是有长度的 json 内容(长度为 87),其中 content 键值内容才为空,所以这里判断条件选择比 87 大的数值即可,比如 100,即大于 100 的表示此页有内容,小于 100 表示此页已爬取完成。
{“state”:{“code”:2000000,“msg”:“Ok”,“tips”:""},“data”:{“currPage”:-1,“content”:""}}
第二、当需要从文本中解析内容时,不能直接解析,需要先转换。
通常情况下,我们在解析内容时是直接对返回的 response 进行解析,比如使用 response.css() 方法,但此处,我们的解析对象不是 response,而是 response 返回的 json 内容中的 html 文本,文本是不能直接使用 .css() 方法解析的,所以在对 html 进行解析之前,需要添加下面一行代码转换后才能解析。
contents = scrapy.Selector(text=contents, type=“html”)
结果如下,可以看到发送了全部 48 个请求,实际上该分类只有 22 页内容,即多发送了无用的 26 个请求。
▌While 循环
接下来,我们使用 While 循环再次尝试抓取,代码省略了和 For 循环中相同的部分:
def start_requests(self):
page = 2 # 设置爬取起始页数
dict = {‘page’:page,‘cate_code’:cate_code,‘child_cate_code’:child_cate_code} # meta传递参数
yield scrapy.Request(category_url,callback=self.parse,meta=dict)
def parse(self, response):
if len(response.body) >= 100: # 判断该页是否爬完,数值定为100是因为无内容时长度是87
page = response.meta[‘page’]
cate_code = response.meta[‘cate_code’]
child_cate_code = response.meta[‘child_cate_code’]
#…
for content in contents:
yield item
while循环构造url递归爬下一页
page += 1
params = {
‘catId’: cate_code,
‘subCatId’: child_cate_code,
‘page’: page,
}
ajax_url = self.ajax_url + urlencode(params)
dict = {‘page’:page,‘cate_code’:cate_code,‘child_cate_code’:child_cate_code}
yield scrapy.Request(ajax_url,callback=self.parse,meta=dict)
这里,简要说明几点:
第一、While 循环的思路是先从头开始爬取,使用 parse() 方法进行解析,然后递增页数构造下一页的 URL 请求,再循环解析,直到爬取完最后一页即可,这样 不会像 For 循环那样发送无用的请求。
第二、parse() 方法构造下一页请求时需要利用 start_requests() 方法中的参数,可以 使用 meta 方法来传递参数。
运行结果如下,可以看到请求数量刚好是 22 个,也就完成了所有页面的 App 信息爬取。
以上,就是本文的所有内容,小结一下:
在爬取不确定页数的网页时,可以采取 For 循环和 While 循环两种思路,方法大致相同。
在 Requests 和 Scrapy 中使用 For 循环和 While 循环的方法稍有不同,因此本文以豌豆荚网站为例,详细介绍了循环构造方法。
转载于:https://www.cnblogs.com/sanduzxcvbnm/p/10277313.html
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
// An highlighted block
var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
- 计划任务
- 完成任务
创建一个表格
一个简单的表格是这么创建的:
项目 | Value |
---|---|
电脑 | $1600 |
手机 | $12 |
导管 | $1 |
设定内容居中、居左、居右
使用:---------:
居中
使用:----------
居左
使用----------:
居右
第一列 | 第二列 | 第三列 |
---|---|---|
第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' |
‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" |
“Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash |
– is en-dash, — is em-dash |
创建一个自定义列表
-
Markdown
- Text-to- HTML conversion tool Authors
- John
- Luke
如何创建一个注脚
一个具有注脚的文本。2
注释也是必不可少的
Markdown将文本转换为 HTML。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
新的甘特图功能,丰富你的文章
- 关于 甘特图 语法,参考 这儿,
UML 图表
可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:
这将产生一个流程图。:
- 关于 Mermaid 语法,参考 这儿,
FLowchart流程图
我们依旧会支持flowchart的流程图:
- 关于 Flowchart流程图 语法,参考 这儿.
导出与导入
导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
-
注脚的解释 ↩︎