这不是一个很难的项目,没有ajax请求,也没有用框架,只是一个requests请求和BeautifulSoup的解析
不过,看这段代码你会发现,BeautifulSoup不止只有find和fing_all用于元素定位,还有fing_next等其他的更简单的,你如果某事觉得xpath比BeautifulSoup更简单,那你真的应该结合我这个再把BeautifulSoup文档再看一遍,你会发现基于lxml解析的BeautifulSoup更强大
当然代码中还有一些小的细节,可以让你学到一些东西。比如,对象的传入,如何避免频繁的IO操作
那接下来就贴代码了,代码中有注释,没有什么好解释的,所以接下来就只剩下代码和代码的注释了! 如果有不懂得可以私信。
# _*_ coding:utf-8 _*_
import time,csv
from random import uniform,choice
import requests
from bs4 import BeautifulSoup
cities = ['bj', 'sh', 'nj', 'wh', 'cd', 'xa','hf']
# 一个我们将要爬取城市的列表
def get_city():
global cities
try:
city = choice(cities)
cities.remove(city)
# 随机选取一个城市进行爬取,然后再列表中删除这个城市
print(cities)
except IndexError:
return None
# 当没有城市了,就返回一个None
return city
def get_url(index,city):
if city == None:
return
# 城市值为None时,我们就跳出
else:
if index == 1:
url = 'https://{city}.lianjia.com/zufang/'.format(city=city)
return url
# 这是首页链接
else:
url = 'https://{city}.lianjia.com/zufang/pg{index}'.format(index=index,city=city)
return url
def get_ressponse(url,file,headers):
html = requests.get(url=url,headers=headers,verify=False)
Soup = BeautifulSoup(html.text,'lxml')
house_list = Soup.find(attrs={'id':'house-lst'}).find_all('li')
for li in house_list:
detail_mes = li.a['href']
img_house = li.img['src']
title = li.h2.a.get_text(strip=True)
region = li.find_next(attrs={'class':'where'}).a.get_text(strip=True)
zone = li.find_next(attrs={'class':'zone'}).span.get_text(strip=True)
meters = li.find_next(attrs={'class':'meters'}).get_text(strip=True)
directory = li.find_next(attrs={'class':'meters'}).find_next_sibling('span').get_text()
other = li.find_next(attrs={'class':'other'}).find('div').get_text(strip=True)
chanquan = li.find_next(attrs={'class':'chanquan'}).get_text(strip=True)
file.writerow([detail_mes,img_house,title,region,zone,meters,directory,other,chanquan])
# 我们将传进一个csv的写的对象,对文件进行写操作
def main(city):
for index in range(1, 101):
try:
if index == 1 or index == 2:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Referer': 'https://{city}.lianjia.com/zufang/pg3'.format(city=city),
# 我们动态的调换跳转的页面,觉得更像人的点击行为
'Host': '{city}.lianjia.com'.format(city=city),
# 这里我们动态的调换要访问的主机
}
else:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Referer': 'https://{city}.lianjia.com/zufang/pg3'.format(city=city,index=index-1),
'Host': '{city}.lianjia.com'.format(city=city),
}
# 注意这里的请求头我们在不同的情况下值是不一样的
# 当然请求头你不换也许并不会导致出错,但是这也是一种反爬虫的方法,学习一下?
url = get_url(index,city)
get_ressponse(url=url, file=writer,headers=headers)
# 将请求头传入
# 传进链接和写对象
t = uniform(1, 3)
time.sleep(t)
# 强制要求请求休息一下,我们这里用1,3之间的随机数
except AttributeError:
print('我发现了一个错误')
except UnicodeEncodeError:
print('有一个编码错误')
# 两个错误检查
if __name__ == '__main__':
with open('D:/scrapy的message/lianjia.csv','a',encoding='utf-8') as f:
# 因为默认的读写操作是gbk,所以最好还是改成utf-8
# 在这里打开文件而不是在循环中打开,我们就可以避免频繁的IO操作
writer = csv.writer(f)
# 创建一个写对象
writer.writerow(['detail_mes','img_house','title','region','zone,meters','directory','other','chanquan'])
# 写入表头
for x in range(0,100):
city = get_city()
time.sleep(10)
# 城市间的跳转等待时间稍微长一点,毕竟我们要更友好对不对!
print('正在爬取的城市是:%s' % city)
if city == None:
break
# 如果没有城市了,那就跳出循环停止了。
main(city)
按照惯例,我应该贴一下我的成果:
可以看到一共6千多数据除以2,哈哈哈哈哈哈哈!!!!!
改进之后就可以实现万级数据的爬取了,当然我并没有然他运行完成,还会更多哦