序言
各位大佬,本人为完全零基础的新人一枚,最近在新学习爬虫,回顾来到这的三个多月时间,一点一滴,一分一秒都不是那么轻松容易,但是我相信我的选择是正确的,本博文完全是为了记笔记自用,有些啰嗦,敬请见谅,同时记录的有什么问题也希望各位大佬高抬贵手给予指出,感谢!!!!!!!
本次为使用xpath对网页数据进行抓取并使用MongoDB对数据进行保存,同时使用进程池(线程池)提高抓取速度:
1.获取网页源代码
我们以链家网为列:
https://cs.lianjia.com/ershoufang/pg1/
然后再将自己的User-Agent找到:
同时切换页面,发现不同页面的地址不一样,
第一页:https://cs.lianjia.com/ershoufang/pg1/
第二页:https://cs.lianjia.com/ershoufang/pg2/
第三页:https://cs.lianjia.com/ershoufang/pg3/
也就是说换页只需向网页最后面的pg传递参数就行,现在可以对网页源代码进行获取,并写入一个执行主程序:
# -*- coding:utf-8 -*-
import pymongo
import requests
from lxml import etree
class Er_Fang(object):
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36',
}
def lianjie(self,url_2):
req = requests.get(url_2, headers=self.headers)
if req.status_code == 200:
return req.text
else:
return None
if __name__ == '__main__':
a = Er_Fang()
url = 'https://cs.lianjia.com/ershoufang/pg'
for num in range(1, 6):
url_1 = url + str(num) + '/'
html = a.lianjie(url_1)
print(f'第{num}页获取完毕')
然后开始分析网页查看需爬取图片所在链接:
通过查看审查元素发现所有图片的信息都保存在一个***class="clear LOGCLICKDATA"的div标签里。但通过对网页源码进行确认这里的class与源码中的不一样,如图:
我们再次测试发现标签中有个data-lj_click_event=“SearchClick”***属性与源码中是一致的,那么我们就可以通过这个属性对源码进行拆解并获取我们想要的属性(如何对数据所在位置进行分析并使用xpath进行获取不在说明,请参考我的上一期文章),并将其存入MongoDB数据库:
链接: python爬虫使用xpath及bs4解析数据
def parse_data_index(self,req_1):
html1 = etree.HTML(req_1)#解析网页源码
data_list = html1.xpath('//ul[@class="sellListContent"]//li[@data-lj_click_event="SearchClick"]')#获取含有数据的li标签并放入一个列表里
for shuju in data_list:#遍历列表中的数据
data = {}
title = shuju.xpath('./div[1]/div[1]/a/text()')[0]#获取标题标签
locale = shuju.xpath('./div[1]/div[2]/div/a[1]/text()')[0] + '-' + shuju.xpath('./div[1]/div[2]/div/a[2]/text()')[0]#获取位置信息并进行拼接
shape = shuju.xpath('./div[1]/div[3]/div/text()')[0]#获取户型信息
Price = shuju.xpath('./div[1]/div[6]/div[1]/span/text()')[0] + shuju.xpath('./div[1]/div[6]/div[1]/i[2]/text()')[0]#获取总价
Unit_Price = shuju.xpath('./div[1]/div[6]/div[2]/span/text()')[0]#获取单价
#将数据存入一个字典
data = {
'标题':title,
'位置':locale,
'户型':shape,
'总价':Price,
'单价':Unit_Price
}
#创建数据库链接
client = pymongo.MongoClient(host='127.0.0.1', port=27017)
#链接数据库
db = client['erfang']
#将数据写入数据库
db.lianjia.insert_one(dict(data))
这个获取程序就写好了,如果我们需要获取n个页面的数据,这样一个页面一个页面的获取就比较慢,那么我们就可以引入线程池或进程池:
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
现在我们对原来的程序进行修改,只需对入口函数进行修改,并加入时间进行测试:
不加进程池的运行结果:
if __name__ == '__main__':
a = Er_Fang()
url = 'https://cs.lianjia.com/ershoufang/pg'
#获取开始时间
start_time = time.time()
#创建线程池
with ThreadPoolExecutor(5) as b:
#使用进程池也是一样的操作
#with ProcessPoolExecutor(5) as b:
for num in range(1, 20):
print(num)
url_1 = url + str(num) + '/'
print(f'第{num}页储存完毕')
#向进程池放入程序,并传递参数
b.submit(a.lianjie, url_1)
print('花费时间为:',time.time()-start_time)
运行后结果为:
可以看到未使用进程池(线程池)之前抓取9页数据用了7秒多,使用后抓取19页数据只用了3秒多,可见使用进程池(线程池)对爬虫的速度提升是很大的。
代码
# -*- coding:utf-8 -*-
import time
import pymongo
import requests
from lxml import etree
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
class Er_Fang(object):
def __init__(self):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36',
}
def lianjie(self,url_2):
req = requests.get(url_2, headers=self.headers)
if req.status_code == 200:
self.parse_data_index(req.text)
else:
return None
def parse_data_index(self,req_1):
html1 = etree.HTML(req_1)
data_list = html1.xpath('//ul[@class="sellListContent"]//li[@data-lj_click_event="SearchClick"]')
for shuju in data_list:
data = {}
title = shuju.xpath('./div[1]/div[1]/a/text()')[0]
locale = shuju.xpath('./div[1]/div[2]/div/a[1]/text()')[0] + '-' + shuju.xpath('./div[1]/div[2]/div/a[2]/text()')[0]
shape = shuju.xpath('./div[1]/div[3]/div/text()')[0]
Price = shuju.xpath('./div[1]/div[6]/div[1]/span/text()')[0] + shuju.xpath('./div[1]/div[6]/div[1]/i[2]/text()')[0]
Unit_Price = shuju.xpath('./div[1]/div[6]/div[2]/span/text()')[0]
data = {
'标题':title,
'位置':locale,
'户型':shape,
'总价':Price,
'单价':Unit_Price
}
# print(data)
client = pymongo.MongoClient(host='127.0.0.1', port=27017)
db = client['erfang']
db.lianjia.insert_one(dict(data))
if __name__ == '__main__':
a = Er_Fang()
start_time = time.time()
url = 'https://cs.lianjia.com/ershoufang/pg'
with ThreadPoolExecutor(5) as b:
for num in range(1, 20):
print(num)
url_1 = url + str(num) + '/'
print(f'第{num}页储存完毕')
b.submit(a.lianjie, url_1)
print('花费时间为:',time.time()-start_time)