使用Pycharm进行爬虫,根据https://python.gotrained.com/scrapy-tutorial-web-scraping-craigslist/ 提供的教程进行尝试。html
爬虫项目的创建须要一系列相关文件,上网查其它资料以及上述教程都是使用了命令提示符进行项目建立,也是比较方便的。安装好scrapy相关环境后,将目录设为须要创建项目的目录,在命令提示符中键入python
scrapy startproject scr # scr为爬虫项目的名称
随后进入项目目录,即键入web
cd scr
而后使用scrapy的genspider指令建立爬虫,并指定将要进行爬虫的网站的URLjson
scrapy genspider jobs newyork.craigslist.org/search/egr # jobs为本身指定的爬虫的名称,后边的URL注意不须要添加https://,由于scrapy会本身添加
这时scrapy会自动在当前目录创建一个python项目,基本框架已经搭好,使用pycharm打开项目,树状图以下图所示api
jobs.py文件此时内容以下浏览器
# -*- coding: utf-8 -*- import scrapy class JobsSpider(scrapy.Spider): name = 'jobs' # 爬虫名称 allowed_domains = ['craigslist.org'] # 此处为修改后扩大范围的URL,为了便于后边的多页抓取操做 start_urls = ['http://newyork.craigslist.org/search/egr/'] # 开始抓取的起点 def parse(self, response): # 爬虫主函数,不能改名,但能够额外添加函数 pass
咱们要抓取该网页的全部职位头衔(即名称),该网页以下图所示框架
在咱们要抓取的部分右键,检查元素(这里是Edge浏览器),能够获得该部分对应的脚本dom
能够发现咱们第一步要抓取的部分为<a>标签中的文本,此标签的标志特征为它的类,即scrapy
class="result-title hdrlnk"
据此,使用以下代码替换pass语句ide
titles = response.xpath('//a[@class="result-title hdrlnk"]/text()').extract()
response为downloader返回的对象,表明该网页的所有源代码,能够经过print(response.body)检视。xpath语句用于提取HTML的特定部分,这里暂不深刻考虑。该语句中:
// 表示从我指定的标签开始而非<html>,这里为a,即<a>。
[@class="result-title hdrlnk"] 表示提取的<a>标签必须为有该指定的类的标签,类都须要写在@后边。
/ 后边表示要提取的内容,text()即表示提取<a>标签的文本。
extract() 表示将源代码中全部知足前两步约束的<a>标签的内容所有提取,若是使用extract_first(),则只提取第一个。
这时运行爬虫,返回的titles为一个列表,所以能够对其循环,将其存储于一个字典中,代码以下
for title in titles: yield {'Title': title}
比较实用的方式是将爬到的数据存储在CSV文件中,scrapy支持csv,json或XML输出。在命令提示行中输入
scrapy crawl jobs -o result.csv # o表明输出,后边为文件名
便可获得该页的所有职位信息,以下图
上述选取标签特征的方式仅能获取某职位的名称,若是想获得更多信息,好比工做地点(括号内容)
上述方法便行不通了,观察脚本,能够发现每个职位都有一个<p>标签语句,其类为“result-info”
若是抓取每个职位对应的p标签,那么该标签的内容就至关于一个”容器“,其中存储了该职位的名称、地点、URL等信息
首先抓取该”容器“
jobs = response.xpath('//p[@class="result-info"]')
语法规则与前文大同小异,此时的jobs为存储全部容器的一个”列表“(也许是),能够进行遍历操做,观察上图脚本,职位名称存储于<a>标签中,工做地址位于<span>标签中,URL信息一样位于<a>标签中,对应的提取代码为
for job in jobs: title = job.xpath('a/text()').extract_first() address = job.xpath('span[@class="result-meta"]/span[@class=' '"result-hood"]/text()').extract_first('')[2:-1] rel_url = job.xpath('a/@href').extract_first() # 相对URL abs_url = response.urljoin(rel_url) # 绝对URL,也可用字符串相加,不过就须要在extract_first()中设置函数参数为‘’ # extract_first()中‘’的意义为当符合向不存在时使输出为空字符串,而非none # [2:-1]的为了去掉工做地址文本中的括号
注释:xpath语句中的‘/’表示下一子级,‘[ ]’表示特征属性,须要用‘@’做前缀。
这样,再次运行爬虫,在命令提示符中输入
scrapy crawl -o result_op.csv
获得的输出表格以下图所示
下面进一步考虑多页码的状况,网页自己每每不仅有一页,为了自动爬遍全部存在信息的网页,能够对该网页的翻页按钮‘next’进行检视
利用其class属性,获取其对应的URL,代码为
rel_next_url = response.xpath('//a[@class="button next"]/@href').extract_first() abs_next_url = response.urljoin(rel_next_url)
随后利用scrapy的Request对象(注:目前暂时不明白Request的机理....)进行每页的循环调用(?),使用前须要先import一下
from scrapy import Request
生成Request对象
yield Request(abs_next_url, callback=self.parse)
这里callback能够不写,默认也是parse函数。此时所有的代码为
# -*- coding: utf-8 -*- import scrapy from scrapy import Request class JobsSpider(scrapy.Spider): name = 'jobs' allowed_domains = ['craigslist.org'] start_urls = ['http://newyork.craigslist.org/search/egr/'] def parse(self, response): jobs = response.xpath('//p[@class="result-info"]') for job in jobs: title = job.xpath('a/text()').extract_first() address = job.xpath('span[@class="result-meta"]/span[@class=' '"result-hood"]/text()').extract_first('')[2:-1] # extract_first()中‘’的意义为当符合向不存在时使输出为空字符串,而非none rel_url = job.xpath('a/@href').extract_first() abs_url = response.urljoin(rel_url) yield {'Title': title, 'Address': address, 'URL': abs_url} rel_next_url = response.xpath('//a[@class="button next"]/@href').extract_first() abs_next_url = response.urljoin(rel_next_url) yield Request(abs_next_url, callback=self.parse)
再爬一下,能够发现能爬到的信息涵盖了全部页码的内容。
注:多页码时allowed_domains不能使用默认的URL(默认生成的与start_urls同样),不然仍然只爬当前页的内容。大概意思就是扩大URL的范围。
(待续)