php 循环抓取网页内容(PythonFor和While循环不确定页数的网页需要学习的地方)

优采云 发布时间: 2021-11-22 06:27

  php 循环抓取网页内容(PythonFor和While循环不确定页数的网页需要学习的地方)

  本文转载自以下网站:Python For和While循环爬取页数不确定的网页

  学习的地方

  有两种方法。

  第一种方法使用带有 break 语句的 For 循环。最后一页的页数设置了更大的参数,足以循环遍历所有页。爬行完成后,break会跳出循环,结束爬行。

  第二种方法使用While循环,可以和break语句结合使用,也可以设置初始循环判断条件为True,从头开始循环爬行,直到爬到最后一页,再将判断条件改为False跳出循环并结束爬行。

  Requests 和 Scrapy 分别使用 For 循环和 While 循环来抓取页数不确定的网页。

  摘要:Requests 和 Scrapy 分别使用 For 循环和 While 循环来抓取页面数量不确定的网页。

  我们通常遇到的网站页码的显示形式有以下几种:

  一是将所有页码可视化显示,比如之前爬取的宽和东方财富。

  文章见:

  二是不直观显示网页总数,只能在后台查看。比如之前爬过的虎嗅网络,见文章:

  第三个是我今天要讲的。不知道有多少页,比如豌豆荚:

  对于前两种形式的网页,爬取的方法很简单,只用For循环从第一页爬到最后一页,第三种形式不适用,因为最后一页的编号不知道,所以循环到哪一页无法判断。

  如何解决?有两种方法。

  第一种方法使用带有 break 语句的 For 循环。最后一页的页数设置了更大的参数,足以循环遍历所有页。爬行完成后,break会跳出循环,结束爬行。

  第二种方法使用While循环,可以和break语句结合使用,也可以设置初始循环判断条件为True,从头开始循环爬行,直到爬到最后一页,再将判断条件改为False跳出循环并结束爬行。

  实际案例

  下面,我们以豆豆荚网站中“视频”类别下的App信息为例,通过上述两种方式,抓取该类别下的所有App信息,包括App名称、评论、安装数、和音量。

  先简单分析一下网站,可以看到页面是通过ajax加载的,GET请求自带了一些参数,可以使用params参数构造URL请求,但是不知道怎么做有很多页面。为了保证所有页面都被下载,设置更大的页面数,比如100页甚至1000页。

  下面我们尝试使用For和While循环爬取。

  要求

  ▌For 循环

  主要代码如下:

  类 Get_page():

  def __init__(self):

  #ajax请求地址

  self.ajax_url ='#39;

  def get_page(self,page,cate_code,child_cate_code):

  参数 = {

  'catId': cate_code,

  'subCatId':child_cate_code,

  “页面”:页面,

  }

  response = requests.get(self.ajax_url, headers=headers, params=params)

  content = response.json()['data']['content'] #在json中提取html页面数据

  返回内容

  def parse_page(self, content):

  # 解析网页内容

  内容 = pq(content)('.card').items()

  数据 = []

  对于内容中的内容:

  数据 1 = {

  'app_name': content('.name').text(),

  '安装':内容('.安装计数')。文本(),

  'volume': content('.meta span:last-child').text(),

  '评论':内容('.comment')。文本(),

  }

  数据.附加(数据1)

  如果数据:

  # 写入MongoDB

  self.write_to_mongodb(数据)

  如果 __name__ =='__main__':

  # 实例化数据抽取类

  wandou_page = Get_page()

  cate_code = 5029 # 视频播放的大类号

  child_cate_code = 716 # 视频类别号

  对于范围内的页面 (2, 100):

  打印('*' * 50)

  打印('爬行:页面 %s'% 页)

  content = wandou_page.get_page(page,cate_code,child_cate_code)

  # 添加循环判断,如果内容为空,表示页面已下载,跳出循环

  如果不是内容 =='':

  wandou_page.parse_page(内容)

  sleep = np.random.randint(3,6)

  时间.睡眠(睡眠)

  别的:

  print('该分类的最后一页已下载')

  休息

  在这里,首先创建了一个 Get_page 类。get_page 方法用于获取Response 返回的json 数据。通过网站解析json后,发现要提取的内容是data字段下的content key包裹的一段html文本。使用parse_page方法中的pyquery函数进行解析,最终提取出App名称、评论、安装数、体积这四个信息来完成爬取。

  在main函数中,if函数用于条件判断。如果内容不为空,则表示页面有内容,则循环往下爬,如果为空,则表示页面已经被爬取,执行else分支下的break语句。结束循环并完成爬行。

  爬取结果如下,可以看到该分类下共爬取了41页信息。

  ▌While 循环

  while循环和For循环的思路大致相同,但是有两种写法,一种还是结合break语句,一种是改变判断条件。

  整体代码不变,只修改For循环部分:

  page = 2 # 设置开始爬取的页面数

  而真:

  打印('*' * 50)

  打印('爬行:页面 %s' %page)

  content = wandou_page.get_page(page,cate_code,child_cate_code)

  如果不是内容 =='':

  wandou_page.parse_page(内容)

  页 += 1

  sleep = np.random.randint(3,6)

  时间.睡眠(睡眠)

  别的:

  print('该分类的最后一页已下载')

  休息

  或者:

  page = 2 # 设置开始爬取的页面数

  page_last = False # while 循环初始条件

  虽然不是 page_last:

  #...

  别的:

  # 休息

  page_last = True # 将 page_last 改为 True 跳出循环

  结果如下,可以看到For循环的结果是一样的。

  我们可以测试其他分类下的网页,例如选择“K歌”分类,代码为:718,然后只需要相应修改main函数中的child_cate_code,再次运行程序,即可看到下一个此类别共抓取 32 页。

  由于Scrapy中的写入方式与Requests略有不同,所以接下来我们将再次在Scrapy中实现两种循环爬取方式。

  刮痧

  ▌For 循环

  在Scrapy中使用For循环递归爬取的思路很简单,就是先批量生成所有请求的URL,包括最后一个无效的URL,然后在parse方法中加入if来判断和过滤无效请求,然后抓取所有页面。由于Scrapy依赖Twisted框架,采用异步请求处理方式,也就是说Scrapy在发送请求的同时解析内容,所以这样会发送很多无用的请求。

  def start_requests(self):

  页数=[]

  对于范围内的 i(1,10):

  网址='%s'%i

  page = scrapy.Request(url,callback==self.pare)

  pages.append(页面)

  返回页面

  下面,我们选择豌豆荚“新闻阅读”类别下的“电子书”App页面信息,使用For循环尝试爬取。主要代码如下:

  def start_requests(self):

  cate_code = 5019 # 新闻阅读

  child_cate_code = 940 # 电子书

  打印('*' * 50)

  页数 = []

  对于范围内的页面(2,50):

  打印('爬行:页面 %s' %page)

  参数 = {

  'catId': cate_code,

  'subCatId':child_cate_code,

  “页面”:页面,

  }

  category_url = self.ajax_url + urlencode(params)

  pa = 产出scrapy.Request(category_url,callback=self.parse)

  pages.append(pa)

  返回页面

  定义解析(自我,响应):

  if len(response.body) >= 100: #判断页面是否被爬取,该值设置为100,因为响应的长度为87时没有内容

  jsonresponse = json.loads(response.body_as_unicode())

  内容 = jsonresponse['数据']['内容']

  #响应为json,json内容为html,html为文本不能直接用.css提取,必须先转换

  内容=scrapy.Selector(文本=内容,类型=“html”)

  content = contents.css('.card')

  对于内容中的内容:

  item = 玩豆家Item()

  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()

  产量项目

  上面的代码简单易懂,简单说明几点:

  一、 判断当前页面是否被爬取的判断条件改为response.body的长度大于100。

  因为请求已经爬取完成页面,返回的响应结果不是空的,而是一段json内容的长度(长度为87),这里的内容key值内容为空,所以选择判断条件这里)一个大于87的值就足够了,比如100,大于100表示​​这个页面有内容,小于100表示​​该页面已经被抓取。

  {"state":{"code":2000000,"msg":"Ok","tips":""},"data":{"currPage":-1,"content":""}}

  二、 当需要从文本中解析内容时,无法直接解析,需要先进行转换。

  正常情况下,我们在解析内容的时候直接解析返回的响应,比如使用response.css()方法,但是这里,我们的解析对象不是响应,而是响应返回的json内容中的html文本。文本无法直接使用.css()方法进行解析,所以在解析html之前,需要在解析前添加如下代码行进行转换。

  内容=scrapy.Selector(文本=内容,类型=“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} # 元传递参数

  产生scrapy.Request(category_url,callback=self.parse,meta=dict)

  定义解析(自我,响应):

  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']

  #...

  对于内容中的内容:

  产量项目

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线