Pycharm环境python爬虫初试笔记

使用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的范围。

(待续)