爬取穷游网

1、分析网页url规律

进入穷游网,找到行程助手,点击进去
在这里插入图片描述
然后找到搜索,随便搜索一下,发现地址栏的url支持中文关键字
在这里插入图片描述
查看url规律
在这里插入图片描述
以日本为例,url需要变动的是页码数和关键字
在这里插入图片描述
这个爬虫程序,用进程爬取地区,用协程抓取地区的每一个页面

2、定义函数请求每个地区的页数

在这里插入图片描述
使用xpath匹配页数,使用正则匹配数字,获取最大页数
在这里插入图片描述
qiongyou_1 .py

import multiprocessing
import re
import requests
import gevent
from gevent import monkey
monkey.patch_all()
from lxml import etree
from time import sleep


# 定义一个函数请求每隔地区的首页
def fetch_areas(url,headers,area):
	
	area_html = requests.get(url=url%(1,area),headers=headers).text
	
	a_tree = etree.HTML(area_html)
	# 使用xpath匹配页数
	lastPage = a_tree.xpath('//a[@class="ui_page_item"]/text()')[-1]
	print(lastPage)
	#使用正则匹配数字,获取最大页数
	totalPages = int(re.findall(pattern=r'\d+',string=lastPage)[0])
	print(totalPages)
	
	# 用协程抓取每一个页面
	# 定义一个列表,用于管理和当前进程中的所有协程
	g_list = []
	for page in range(1,totalPages+1):
		page_url = url%(page,area)
		# 创建一个协程
		g = gevent.spawn(fetch_pages_per_area,page_url,headers)
		g_list.append(g)
	gevent.joinall(g_list)
	


# 定义一个函数,用于请求每个地区的页面信息
def fetch_pages_per_area(url,headers):
	pass
	
	
if __name__ == '__main__':
	#定义一个列表,规定要抓取的那些地区
	areas =['中国','欧洲','泰国','韩国','日本','新加坡','南美洲']
	
	url = 'http://plan.qyer.com/search_0_0_0_0_0_0_%d/?keyword=%s'
	# 请求头
	headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'}
	
	#对于计算密集型的程序,一般用进程,线程,协程都行;但对于I/O密集型的程序,一般不用进程
	
	# 用进程完成每个地区的请求
	p_list = []
	for area in areas:
		# 创建进程
		p = multiprocessing.Process(target=fetch_areas,args=(url,headers,area))
		p.start()
		p_list.append(p)
		
	for p in p_list:
		p.join()

运行一下,可以获取
在这里插入图片描述
(monkey模块可能会报错,但不影响数据的获取)

3、定义函数请求每个地区的页面信息

在这里插入图片描述
使用xpath匹配信息
然而,不是所有都是那么顺利,如果就按造xpath匹配的内容获取,会有出错的地方,有些不匹配
比如匹配标题,有一些没有标题,或者url不匹配,打印出来看一下

# 定义一个函数,用于请求每个地区的页面信息
def fetch_pages_per_area(url, headers):
	
	# 打印异常
	try:
		print('当前正在请求:',url)
		res = requests.get(url=url,headers=headers)
		sleep(1)
		
		#解析
		page_tree = etree.HTML(res.text)
		travels = page_tree.xpath('//div[@class="items"]')
		for travel in travels:
			item ={}
			item['title'] = travel.xpath('.//dd/text()')[0]
			print(item)
	
	except Exception as e:
		print('url:%s出异常了'%url)
		print(e)
		

在这里插入图片描述
还是有一些这种情况的

于是,这些出错的,把那一项就设为空,也是一个方法

qiongyou_2 .py

import multiprocessing
import re
import requests
import gevent
from gevent import monkey

monkey.patch_all()
from lxml import etree
from time import sleep


# 定义一个函数请求每隔地区的首页
def fetch_areas(url, headers, area):
	area_html = requests.get(url=url % (1, area), headers=headers).text
	
	a_tree = etree.HTML(area_html)
	# 使用xpath匹配页数
	lastPage = a_tree.xpath('//a[@class="ui_page_item"]/text()')[-1]
	# 使用正则匹配数字,获取最大页数
	totalPages = int(re.findall(pattern=r'\d+', string=lastPage)[0])
	# print(totalPages)
	
	# 用协程抓取每一个页面
	# 定义一个列表,用于管理和当前进程中的所有协程
	g_list = []
	for page in range(1, totalPages + 1):
		page_url = url % (page, area)
		# 创建一个协程
		g = gevent.spawn(fetch_pages_per_area, page_url, headers)
		g_list.append(g)
	gevent.joinall(g_list)


# 定义一个函数,用于请求每隔地区的页面信息
def fetch_pages_per_area(url, headers):
	
		print('当前正在请求:', url)
		res = requests.get(url=url, headers=headers)
		sleep(2)
		
		# 解析
		page_tree = etree.HTML(res.text)
		travels = page_tree.xpath('//div[@class="items"]')
		for travel in travels:
			item = {}
			item["title"] = travel.xpath(".//dd/text()")[0] if travel.xpath(".//dd/text()") else " "
			item["start_time"] = travel.xpath(".//dt/text()")[0] if travel.xpath(".//dt/text()") else " "
			item["cycle"] = travel.xpath(".//div[@class='day']//text()")[0] if travel.xpath(
				".//div[@class='day']//text()") else " "
			tag = travel.xpath(".//div[starts-with(@class,'tag')]//text()")
			if len(tag) != 0:
				item["tag"] = " ".join(tag)
			else:
				item["tag"] = "自由行"
			item["plan"] = travel.xpath(".//div[@class='plan']/p/text()")[0] if travel.xpath(
				".//div[@class='plan']/p/text()") else " "
			item["next_url"] = "http:" + travel.xpath(".//a[@class='link']/@href")[0] if travel.xpath(
				".//a[@class='link']/@href") else " "
			print(item)
	
	


if __name__ == '__main__':
	# 定义一个列表,规定要抓取的那些地区
	areas = ['中国', '欧洲', '泰国', '韩国', '日本', '新加坡', '南美洲']
	
	url = 'http://plan.qyer.com/search_0_0_0_0_0_0_%d/?keyword=%s'
	# 请求头
	headers = {
		'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'}
	
	# 对于计算密集型的程序,一般用进程,线程,协程都行;但对于I/O密集型的程序,一般不用进程
	
	# 用进程完成每个地区的请求
	p_list = []
	for area in areas:
		# 创建进程
		p = multiprocessing.Process(target=fetch_areas, args=(url, headers, area))
		p.start()
		p_list.append(p)
	
	for p in p_list:
		p.join()

4、数据的存储

换汤不换药,最后就是数据的存储了
这里偷下懒,直接存到redis数据库中,就不存csv文件了,其实也就是多加两行代码的事

qiongyou_3 .py

import multiprocessing
import re
import requests
import redis
import gevent
from gevent import monkey
monkey.patch_all()

from lxml import etree
from time import sleep


# 定义一个函数请求每隔地区的首页
def fetch_areas(url, headers, area):
	area_html = requests.get(url=url % (1, area), headers=headers).text
	
	a_tree = etree.HTML(area_html)
	# 使用xpath匹配页数
	lastPage = a_tree.xpath('//a[@class="ui_page_item"]/text()')[-1]
	# 使用正则匹配数字,获取最大页数
	totalPages = int(re.findall(pattern=r'\d+', string=lastPage)[0])
	# print(totalPages)
	
	# 用协程抓取每一个页面
	# 定义一个列表,用于管理和当前进程中的所有协程
	g_list = []
	for page in range(1, totalPages + 1):
		page_url = url % (page, area)
		# 创建一个协程
		g = gevent.spawn(fetch_pages_per_area, page_url, headers)
		g_list.append(g)
	gevent.joinall(g_list)


# 定义一个函数,用于请求每隔地区的页面信息
def fetch_pages_per_area(url, headers):
	print('当前正在请求:', url)
	res = requests.get(url=url, headers=headers)
	sleep(2)
	
	# 解析
	page_tree = etree.HTML(res.text)
	travels = page_tree.xpath('//div[@class="items"]')
	for travel in travels:
		item = {}
		item["title"] = travel.xpath(".//dd/text()")[0] if travel.xpath(".//dd/text()") else " "
		item["start_time"] = travel.xpath(".//dt/text()")[0] if travel.xpath(".//dt/text()") else " "
		item["cycle"] = travel.xpath(".//div[@class='day']//text()")[0] if travel.xpath(
			".//div[@class='day']//text()") else " "
		tag = travel.xpath(".//div[starts-with(@class,'tag')]//text()")
		if len(tag) != 0:
			item["tag"] = " ".join(tag)
		else:
			item["tag"] = "自由行"
		item["plan"] = travel.xpath(".//div[@class='plan']/p/text()")[0] if travel.xpath(
			".//div[@class='plan']/p/text()") else " "
		item["next_url"] = "http:" + travel.xpath(".//a[@class='link']/@href")[0] if travel.xpath(
			".//a[@class='link']/@href") else " "
		print(item)
		
		rds = redis.StrictRedis(host='127.0.0.1',port=6379,db=9)
		rds.lpush('plans',item)


if __name__ == '__main__':
	# 定义一个列表,规定要抓取的那些地区
	areas = ['中国', '欧洲', '泰国', '韩国', '日本', '新加坡', '南美洲']
	
	url = 'http://plan.qyer.com/search_0_0_0_0_0_0_%d/?keyword=%s'
	# 请求头
	headers = {
		'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'}
	
	# 对于计算密集型的程序,一般用进程,线程,协程都行;但对于I/O密集型的程序,一般不用进程
	
	# 用进程完成每个地区的请求
	p_list = []
	for area in areas:
		# 创建进程
		p = multiprocessing.Process(target=fetch_areas, args=(url, headers, area))
		p.start()
		p_list.append(p)
	
	for p in p_list:
		p.join()

连csv都不存了,是不是过分?

这里有一个问题,如果爬多了,会遇到反爬,就涉及到ip代理了

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值