Scrapy爬取链家二手房信息,并存为.csv文件——第一个完整爬取项目
1.打开Pycharm,进入Terminal
创建爬虫项目:scrapy startproject Ljhouse
进入项目:cd Ljhouse
设置爬虫名和爬虫域名:scrapy genspider Lj bj.lianjia.com
//该项目爬取的是链家网站上,北京地区的二手房信息 网页链接
2.修改settings设置
设置请求代理为谷歌浏览器的User_Agnet
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'
不遵循机器人协议
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
下载延迟为1s:DOWNLOAD_DELAY = 1
设置管道,用于爬取数据的处理
ITEM_PIPELINES = {
'Ljhouse.pipelines.LjhousePipeline': 300,
}
3.定义要爬取的items,计划爬取标题、地址以及总价的信息
title、address、price为字典类型,初始没有赋值
import scrapy
class LjhouseItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
address = scrapy.Field()
price = scrapy.Field()
#pass
4.分析网页,查找items所在位置(标签名称)
F12检查发现,所需二手房信息均在ul[@calss=“sellListContent”]的标签下,单个二手房的信息在标签li[@calss=“clear LOGCLICKDATA”]中
但查阅更多li标签时发现,其class内容发生变化。
对比网页进行检查发现:在鼠标扫过二手房信息后,li的class会由初始的clear LOGVIEWDATA LOGCLICKDATA 变为clear LOGCLICKDATA,因此在进行位置捕获时,应使用初始class:clear LOGVIEWDATA LOGCLICKDATA。
进一步分析li内部标签发现,所需要的标题信息在div[@clas=“title”]中的超连接标签中
5根据网页源码分析,使用.xpth()进行内容获取
.xpath语法:
/表示在根节点向下寻找
//表示从当前节点向下寻找
.表示选取当前节点
. .表示选取当前节点的父节点
@表示匹配属性值
text()表示输出文本内容
标题内容选取:
.//div[@class=“title”]/a/text()
同理可得,其他标签内容选取语句
#爬取li标签中的所有信息
list = response.xpath('//ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]')
for li in list:
#依次提取title address price
items["title"] = li.xpath('.//div[@class="title"]/a/text()').get()
items["address"] = li.xpath('.//div[@class="positionInfo"]/a[1]/text()').get()
items["price"] = li.xpath('.//div[@class="totalPrice"]/span/text()').get()
附一个详细的xpath语法学习链接:xpath语法学习
6.改写爬虫文件,使之循环爬取两页信息
Lj.py代码整体如下:
注意注意!爬虫页数pg从2开始,不能从1开始,否则会重复爬取第一页!
import scrapy
#引入刚刚写好的item
from ..items import LjhouseItem
class LjSpider(scrapy.Spider):
name = 'Lj'
allowed_domains = ['bj.lianjia.com']
start_urls = ['https://bj.lianjia.com/ershoufang/pg{}/'.format("1")]
n = 2
def parse(self, response):
items = LjhouseItem()
#爬取li标签中的所有信息
list = response.xpath('//ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]')
for li in list:
#依次提取title address price
items["title"] = li.xpath('.//div[@class="title"]/a/text()').get()
items["address"] = li.xpath('.//div[@class="positionInfo"]/a[1]/text()').get()
items["price"] = li.xpath('.//div[@class="totalPrice"]/span/text()').get()
#它的作用是移交控制权,在本程序中,我们对item封装数据后,就调用yield把控制权给管道,管道拿到处理后return返回,又回到该程序。
yield items
#循环抓取不同页面 从第二页开始,因为初始url已经爬取第一页
for pg in range(2,3):
if self.n <= 2:
self.n += 1
#将页码数加之url(存在列表中)末尾,使之成为新的url
url = self.start_urls[0].format(str(pg))
#这条程序里利用了一个回调机制,即callback, 回调的对象是parse, 也就是当前方法,通过不断的回调,程序将陷入循环
#self.parse() 和 self.parse 前者是执行 后者是地址
#解决爬取重复 添加dont_filter=True
yield scrapy.Request(url=url,callback=self.parse,dont_filter=True)
7.编写run.py,运行爬虫程序
from scrapy import cmdline
cmdline.execute('scrapy crawl Lj -o Lj_test3.csv'.split())
查看csv文件发现,内容出现乱码
解决方法,在settings中设置写入编码
#设置文本编码,使导出的csv文件中不出现中文编码
FEED_EXPORT_ENCODING = 'gb18030'
重新运行爬虫,成功!
终于终于,在码了多个BUG以后,终于成功实现了第一个小的爬虫项目!(继续努力!)