scrapy框架爬虫案例1-----赶集网
作者:互联网
文章目录
1.蜘蛛侠思路:
赶集网
爬取网站的url地址:点击超链接-----赶集网主页-------
步骤一:开始爬虫的第一步应该是要先明确需要爬取的目标网址,这就需要花一些时间了解网站的大致结构,以及明确自己想要获取的数据,并且需要知道这些数据是通过什么方式展现出来的,这就需要查看网站的源代码,如果网站源代码中没有这些数据,就需要考虑其是否是用ajax等方式发送的。
步骤二:观察切换页码时url地址的规律变化
步骤三:观察详情页url地址的规律变化,编写代码
-点击【切换城市】转到有所有城市的主页
2.构造爬虫及代码解读
你可以通过cmd构建爬虫,也可以直接使用pycharm中自带的终端构建爬虫
#创建爬虫项目
scrapy startproject ganji_crawl
#创建爬虫
scrapy genspider ganji anshan.ganji.com
身为一个蜘蛛侠,首先就是需要猥琐,不能让网站知道你是蜘蛛侠,超人都需要隐藏身份,所以我们先写好
settings.py
文件,把自己伪装成浏览器,让网站不知道我们是蜘蛛侠,然后再写爬虫,以免暴露身份,我把每个文件都分成了单个函数来讲解,这样更方便理解一下,合在一起就是完整的了。
(1)settings.py
爬取一些简单的网站,不需要修改那么多,简单改一下就行了。
LOG_LEVEL='WARNING' #日志的输出等级,不想看那么多日志信息就可以写成WARNING
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'#把自己伪装成浏览器
ROBOTSTXT_OBEY = False #不遵从机器人协议
#把注释去掉就行
ITEM_PIPELINES = {
'erShouFang.pipelines.ErshoufangPipeline': 300,
}
USER_AGENT随便打开一个网站按F12就能找到,不同浏览器的USER_AGENT是不一样的
(2)ganji.py
import scrapy
import re
from ..items import ErshoufangItem
class GanjiSpider(scrapy.Spider):
name = 'ganji' #爬虫名,运行的关键参数
start_urls = ['http://www.ganji.com/index.htm']
def start_requests(self):
for urls in self.start_urls:
yield scrapy.Request(url=urls,callback=self.parse_province)
通过
start_urls
对赶集网主页发起请求。重写start_requests
方法,一般不直接用parse函数,构造一个新函数会更好;这里通过callback回调了一个新的函数parse_province
def parse_province(self,response):
all_city_href = response.xpath('.//div[@class="all-city"]/dl/dd/a/@href').extract()[:1] #300个城市中选前1个
for city_href in all_city_href:
yield scrapy.Request(url=city_href+"zufang",callback=self.parse_detail_urls)
1.定义了一个解析主页所有城市超链接的函数,获取到所有城市的超链接,由于条件有限,这里就只获取第一个url,如果你想一口气干到底,你可以试着把
[:1]
这个限制去掉… 学到这个思路就好
/
2.extract()
返回的是一个列表extract_first()
返回列表第一个元素,get()
返回一个字符串
/
3.all_city_href
获取到的url是不完整,所以还需要拼接一下才能请求到目标网址
/
4.callback
回调函数,通过获取到的url发起新的请求
5.url = http://anshan.ganji.com/zufang/ , zufang=租房,二手房=ershoufang …
通过观察网站,我们发现详情页有我们需要的所有数据,所以这里我直接获取详情页的数据就行了。
我删
def parse_detail_urls(self,response):
print("province_urls:" + response.url)
all_detail_url = response.xpath('.//dd[@class="dd-item title"]/a/@href').extract()
for detail_url in all_detail_url:
if "http" in detail_url:
yield scrapy.Request(url=detail_url,callback=self.parse_detail)
if "http" not in detail_url:
yield scrapy.Request(url="http:"+detail_url,callback=self.parse_detail)
next_url = response.xpath('.//a[@class="next"]/@href').get()
if next_url:
yield scrapy.Request(url=next_url, callback=self.parse_detail_urls)
1.定义一个获取详情页url和实现自动翻页的函数,至于加这个 http 的判断是因为获取的详情页url中有一些是不完整的,所以需要加个判断
2.next_url
获取下一页的url地址,通过callback
回调自己,实现自动翻页,不需要再去看网站有多少一页,再写个循环了…
3.获取到下一页的url地址,如果这个url存在,就说明有下一页呗。
def parse_detail(self,response):
print("detail_ulrs:"+response.url)
item = ErshoufangItem() #存储
item['title'] = response.xpath('normalize-space(.//title/text())').get()
item['money'] = response.xpath('.//div[@class="price-wrap"]/span[1]/text()').get()
item['ya_type'] = response.xpath('.//div[@class="price-wrap"]/span[2]/text()').get()
item['huxing'] = response.xpath('.//ul[@class="er-list f-clear"]/li[1]/span[2]/text()').get()
mianji = response.xpath('.//ul[@class="er-list f-clear"]/li[2]/span[2]/text()').get()
item['zu_type'] =re.findall('\w{2}',mianji)[0]
item['pingfa'] =re.findall('\w{2}',mianji)[1]
item['chaoxiang'] = response.xpath('.//ul[@class="er-list f-clear"]/li[3]/span[2]/text()').get()
louceng = response.xpath('.//ul[@class="er-list f-clear"]/li[4]/span[2]/text()').get()
item['cengshu'] = re.findall('\d+',louceng)[0]
item['zhuangxiu'] = response.xpath('.//ul[@class="er-list f-clear"]/li[5]/span[2]/text()').get()
item['xiaoqu'] = response.xpath('.//ul[@class="er-list-two f-clear"]/li[1]/span[2]/a/span/text()').get()
item['ditie'] = response.xpath('.//ul[@class="er-list-two f-clear"]/li[2]/div/span/text()').get()
item['dizhi'] = response.xpath('normalize-space(.//ul[@class="er-list-two f-clear"]/li[3]/span[2]/text())').get()
item['name'] = response.xpath('.//div[@class="user-info-top"]/div[1]/a/text()').get()
yield item
1.xpath获取详情页数据就得了,不想多说,逻辑到这里就差不多结束了,剩下的搬砖就行。
2.normalize-space()
可以直接去掉\n,\t空格等,就不需要再多写代码去空格了
3.mianji
获取到的数据是这样的 “整租 106㎡”,通过正则把他们切分一下,只取数字
4.louceng
获取到 “共1层”,通过正则只取数字,到这里就完成了对数据的简单清洗
(3)run.py
from scrapy import cmdline
cmdline.execute('scrapy crawl ganji'.split())
编写运行的类
(4)items.py
需要存储什么就写什么
class ErshoufangItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field()
money = scrapy.Field()
ya_type = scrapy.Field()
huxing = scrapy.Field()
zu_type = scrapy.Field()
pingfa = scrapy.Field()
chaoxiang = scrapy.Field()
cengshu = scrapy.Field()
zhuangxiu = scrapy.Field()
xiaoqu = scrapy.Field()
ditie = scrapy.Field()
dizhi = scrapy.Field()
name = scrapy.Field()
(5)pipelines.py
class ErshoufangPipeline(object):
def __init__(self):
# self.connect = pymysql.connect(host='localhost',user='root',passwd='123456',db='ershoufang')
# self.cursor = self.connect.cursor()
self.file =codecs.open('./zufang.json','w','utf-8')
self.dic = ""
1.
class ErshoufangPipeline(object):
加上(object)
2.self.connect
,self.cursor
定义mysql数据库连接,可以把数据存储到数据库
3.self.dic = ""
铺垫一下,方便 后面存储为字典
def process_item(self, item, spider):
# sql="""
# insert into table(title,money) values(%s,%s)
# """
# self.cursor.execute(sql,(item['title'],item['money']))
# self.connect.commit() #提交
lines = json.dumps(dict(item),ensure_ascii=False)+",\n"
self.dic+=lines
return item
def close_spider(self,spider):
self.file.write("[{0}]".format(self.dic[:-2]))
self.file.close()
# self.connect.close()
# self.cursor.close()
1.
self.file.write("[{0}]".format(self.dic[:-2]))
,写入文件,这样可以转化为json格式,不然存储的时候会爆红,不是json格式。
2.[:-2]
就是不要最后的两个字符串 “,\n”
(6)前十条数据
[{"title": "红岭家园 2室1厅1卫,鞍千路 - 赶集网", "money": "900", "ya_type": "半年付", "huxing": "2室1厅1卫", "zu_type": "整租", "pingfa": "66", "chaoxiang": "南北", "cengshu": "22", "zhuangxiu": "简单装修", "xiaoqu": "红岭家园", "ditie": "暂无信息", "dizhi": "立山立山广场 - 鞍千路", "name": "696882"},
{"title": "华润置地广场 1室0厅1卫,建国大道,近民生西路 - 赶集网", "money": "1300", "ya_type": "押一付一", "huxing": "1室0厅1卫", "zu_type": "整租", "pingfa": "50", "chaoxiang": "西", "cengshu": "27", "zhuangxiu": "精装修", "xiaoqu": "华润置地广场", "ditie": "暂无信息", "dizhi": "铁东二一九 - 建国大道,近民生西路", "name": "置家"},
{"title": "解放西路52号小区 1室1厅1卫,解放西路52乙号 - 赶集网", "money": "400", "ya_type": "年付", "huxing": "1室1厅1卫", "zu_type": "整租", "pingfa": "40", "chaoxiang": "南北", "cengshu": "6", "zhuangxiu": "简单装修", "xiaoqu": "解放西路52号小区", "ditie": "暂无信息", "dizhi": "铁西九街口 - 解放西路52乙号", "name": "hbjes_au6"},
{"title": "铁东一道街 3室2厅1卫 - 赶集网", "money": "1000", "ya_type": "半年付", "huxing": "3室2厅1卫", "zu_type": "整租", "pingfa": "86", "chaoxiang": "东西", "cengshu": "6", "zhuangxiu": "简单装修", "xiaoqu": null, "ditie": "暂无信息", "dizhi": "铁东站前", "name": "王先生"},
{"title": "调军台小区 1室1厅1卫,鞍千路 - 赶集网", "money": "950", "ya_type": "押一付三", "huxing": "1室1厅1卫", "zu_type": "整租", "pingfa": "55", "chaoxiang": "东南", "cengshu": "17", "zhuangxiu": "精装修", "xiaoqu": "调军台小区", "ditie": "暂无信息", "dizhi": "立山立山广场 - 鞍千路", "name": "吴女士"},
{"title": "烈士山社区 1室1厅1卫,胜利南路26号 - 赶集网", "money": "350", "ya_type": "年付", "huxing": "1室1厅1卫", "zu_type": "整租", "pingfa": "50", "chaoxiang": "西北", "cengshu": "8", "zhuangxiu": "简单装修", "xiaoqu": "烈士山社区(民生东路北)", "ditie": "暂无信息", "dizhi": "铁东二一九 - 胜利南路26号", "name": "蓝眼泪335"},
{"title": "中天社区 3室2厅1卫,铁东二道街 - 赶集网", "money": "1500", "ya_type": "年付", "huxing": "3室2厅1卫", "zu_type": "整租", "pingfa": "15", "chaoxiang": "东南", "cengshu": "6", "zhuangxiu": "精装修", "xiaoqu": "中天社区", "ditie": "暂无信息", "dizhi": "铁东站前 - 铁东二道街", "name": "宁女士"},
{"title": "联盟社区 3室0厅1卫,联盟街11号 - 赶集网", "money": "500", "ya_type": "半年付", "huxing": "3室0厅1卫", "zu_type": "整租", "pingfa": "73", "chaoxiang": "南北", "cengshu": "7", "zhuangxiu": "简单装修", "xiaoqu": "联盟社区", "ditie": "暂无信息", "dizhi": "铁东烈士山 - 联盟街11号", "name": "张女士"},
{"title": "红星小区 2室1厅1卫,红星南街22号 - 赶集网", "money": "375", "ya_type": "押一付三", "huxing": "2室1厅1卫", "zu_type": "整租", "pingfa": "68", "chaoxiang": "南", "cengshu": "6", "zhuangxiu": "简单装修", "xiaoqu": "红星小区", "ditie": "暂无信息", "dizhi": "海城永安路 - 红星南街22号", "name": "杨迎女士"},
{"title": "港丽花园 1室1厅1卫,解放东路150号 - 赶集网", "money": "1200", "ya_type": "半年付", "huxing": "1室1厅1卫", "zu_type": "整租", "pingfa": "38", "chaoxiang": "南", "cengshu": "33", "zhuangxiu": "精装修", "xiaoqu": "港丽花园", "ditie": "暂无信息", "dizhi": "铁东解放路 - 解放东路150号", "name": "女士"},
3.蜘蛛侠的小Tips(不是黑丝)
写爬虫的时候用debug模式是非常方便的,如果你不知道怎么用,下面可能会帮到你,如果你会,那就算我没说,因为我也不是很会。 右键run.py选择debug ;
打个断点,至于在什么地方打,比如我想看all_city_href返回了哪些东西,我可以在它后面写个pass打上断点,就不需要print输出了
1.可以看到很多信息,比如请求的状态啊,url啊,等等等…
2.我们点击text右边的view,可以看到获取的数据(网页源代码)
这只蜘蛛结束朴实无法一生,想要练习也可以试着去爬取这个网站的更多城市,二手房、厂房啥的j举一反三,不理解的地方可以一起学习交流。代码不完美的地方请多多谅解,多多指教,多多交流。
标签:url,self,item,scrapy,-----,type,response,赶集网 来源: https://blog.csdn.net/dj_hanhan/article/details/115270067