0X00 前言
本来之前是准备爬取boss直聘的招聘信息,结果boss的反爬还挺恶心,访问页面还得带上cookie,页面的cookie有效时间也只有一分钟,不然只能访问到等待页面,菜鸡落泪
0X01 准备工作
使用到的标准库lxml、requests、re、requests.exceptions、os和openpyxl、random、time。
0X02 分析
相比较boss来说,链家的网站对于爬虫友好得多,当然访问的时候还是得带上headers,不然也是会被识别出来是爬虫,从而被拒绝访问。
分析一下链家的url,举一个例子。/ershoufang/pg1rs双流区/。
他的子域名中的cd就对应着成都市,想要访问其他城市的房源信息就可以通过修改它来达成。
后面路径中的pg1就对应着页数,可以通过修改它来达成翻页的效果。
而rs后面的信息就是我们搜索的内容。
很明显可以看出规律 https:// + city + ./ershoufang/pg +页码+ rs + 搜索内容/
url分析完了,来看看链家的页面:
每一条租房信息都存在一个li标签中。
然后可能是因为他的设置原因,不管数据有再多,也只会显示100页出来,一页30条信息,一共就是3000条信息。
简单分析了一下,就下来就是代码实现。
0X03 代码实现
首先定义了两个全局变量count和total_count,用来记录爬取的页数和爬取的数据总数。
global count
global total_count
还用到了time库来记录程序运行时间。
start = time.time()#开始时间
final = time.time()#结束时间
print('爬取完毕,共花费' + str(final - start) + 's.')
这的话由于爬取的页数为100页,就直接写死了循环次数。
如果不确定页数有多少的话可以通过判断response的信息来判断是否为有效url,或者可以通过获取第一个页面下的总页数从而得知总页数的数量,这偷了个懒。
为了防止访问过于频繁从而导致ip被ban,可以使用sleep将程序挂起几秒,避免访问过于频繁。
for i in range(1, 101):
url = '/ershoufang/pg' + str(i) + 'rs双流区/'
time.sleep(random.randint(0, 3))
main(url)
然后是简单的main函数。
通过get_one_page函数得到页面的返回信息,如果返回不为None,就调用
parse_page函数来解析数据,然后存入表格中。
def main(url):
html_data = get_one_page(url)
if html_data is not None:
parse_page(html_data)
为了防止被ban,多准备几个User-Agent,然后访问的时候随机从里面取一个出来放入headers。
def get_one_page(url):
try:
ua = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/0101 Firefox/77.0",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)"
]
headers = {"User-Agent": random.choice(ua)}
response = requests.get(url=url, headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
return None
然后就通过xpath来获取页面中我们想要的信息。
不过感觉这样显得好笨重,不知道有没有更简单的方法,害
data_text = etree.HTML(html_data)
description = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[1]/a/text()')
address = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[2]/div/a[1]/text()')
specific_situation = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[3]/div/text()')
total_price = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[6]/div[1]/span/text()')
unit_price = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[6]/div[2]/span/text()')
attention = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[4]/text()')
然后通过操作xlsx文件,将我们获得的信息全部存入文件当中。
0X04 完整代码
import os
import random
import time
import openpyxl
import requests
from requests.exceptions import RequestException
from lxml import etree
import re
def get_one_page(url):
try:
ua = [
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/0101 Firefox/77.0",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1",
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB7.0)"
]
headers = {"User-Agent": random.choice(ua)}
response = requests.get(url=url, headers=headers)
if response.status_code == 200:
return response.text
else:
return None
except RequestException:
return None
def parse_page(html_data):
data_text = etree.HTML(html_data)
description = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[1]/a/text()')
address = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[2]/div/a[1]/text()')
specific_situation = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[3]/div/text()')
total_price = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[6]/div[1]/span/text()')
unit_price = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[6]/div[2]/span/text()')
attention = data_text.xpath('//*[@id="content"]/div[1]/ul/li/div[1]/div[4]/text()')
# 打开文件
file_name = '成都市双流区二手房源.xlsx'
global total_count
# 判断文件是否存在
if os.path.exists(file_name):
wb = openpyxl.load_workbook(file_name)
print(file_name + '打开成功!')
ws = wb.active
else:
wb = openpyxl.Workbook() # 创建文件对象
print('文件' + file_name + '创建成功!')
ws = wb.active
ws.append(['房源描述', '地址', '房源情况', '规格', '面积', '总价(万)', '单价(元/平米)', '信息发布情况'])
for i in range(0, len(description)):
price = re.search('单价(\\d*?)元/平米', unit_price[i], flags=0)
list = specific_situation[i].split(' | ')
specification = list[0]
area = re.search('(.*)平米', list[1], flags=0).group(1)
ws.append(
[description[i], address[i], specific_situation[i], specification, area, total_price[i], price.group(1),
attention[i]])
total_count += 1
global count
count += 1
print('第' + str(count) + '页爬取成功!')
wb.save(filename=file_name)
def main(url):
html_data = get_one_page(url)
if html_data is not None:
parse_page(html_data)
if __name__ == '__main__':
global count
global total_count
count = 0
total_count = 0
start = time.time()
for i in range(1, 101):
url = '/ershoufang/pg' + str(i) + 'rs双流区/'
time.sleep(random.randint(0, 3))
main(url)
final = time.time()
print('爬取完毕,共花费' + str(final - start) + 's.')
print('共爬取' + str(count) + '页数据')
print('共爬取' + str(total_count) + '条数据')
0X05 成果图
下次应该会学一学python的数据分析来分析分析爬取到的数据?应该吧,应该不会鸽吧,害。