1 Scrapy 爬蟲完整案例-提升篇
1.1 Scrapy 爬蟲進階案例一
Scrapy 爬蟲案例:東莞陽光熱線問政平臺。
網站地址:http://wz.sun0769.com/index.php/question/questionType?type=4
項目的目標:爬取投訴帖子的編號、帖子的url、帖子的標題,和帖子裡的內容。
案例步驟:
第一步:創建項目。
在 dos下切換到目錄
D:\\scrapy_project
新建一個新的爬蟲項目:scrapy startproject dg_sun
第二步:明確需要爬取的內容字段,分析網站的結構( URL、需要爬取的字段的結構)。
【分析分頁URL地址】
從圖片中看到投訴信息列表有3192頁。
第一頁的鏈接地址:
http://wz.sun0769.com/index.php/question/questionType?type=4&page=0
第二頁的鏈接地址:
http://wz.sun0769.com/index.php/question/questionType?type=4&page=30
最後一頁的鏈接地址:
http://wz.sun0769.com/index.php/question/questionType?type=4&page=95730
通過分析我們得知,每一頁的的鏈接地址page的值遞增30,就是下一頁的地址。
【分析每一條投訴信息】
在列表裡點某條投訴信息,進入到某條投訴詳情頁。
投訴信息的編號、標題、內容如下:
查看這些字段在頁面裡的位置。
通過對頁面的分析,得出需要保存的數據字段在頁面上的位置。
#標題
title=response.xpath('//div[contains(@class, "pagecenterp3")]//strong/text()').extract()[0]
# 編號是標題裡的一部分,通過字符串切片,得到編號的內容。
id =title.split(' ')[-1].split(":")[-1]
# 內容
content =response.xpath('//div[@class="c1 text14_2"]/text()').extract()[0]
#鏈接就是請求返回的URL
url=response.url
第三步:編寫 items.py 文件,設置好需要保存的數據字段。
import scrapy
class SunItem(scrapy.Item):
# define the fields for your item here like:
# 標題
title = scrapy.Field()
# 編號
id = scrapy.Field()
# 內容
content = scrapy.Field()
# 鏈接
url = scrapy.Field()
第四步:創建爬蟲。
在 dos下切換到目錄
D:\\scrapy_project\\dg_sun\\dg_sun\\spiders
用命令 scrapy genspider -t crawl sun " wz.sun0769.com " 創建爬蟲。
第五步:編寫爬蟲文件。
import scrapy,sys,os
# 導入CrawlSpider類和Rule
from scrapy.spiders import CrawlSpider, Rule
# 導入鏈接規則匹配類,用來提取符合規則的連接
from scrapy.linkextractors import LinkExtractor
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(path)
from dg_sun.items import SunItem
class SunSpider(CrawlSpider):
name = 'sun'
allowed_domains = ['wz.sun0769.com']
start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=0']
#多條 Rule
rules = (
Rule(LinkExtractor(allow=r'type=4&page=\\d+')),
Rule(LinkExtractor(allow=r'/html/question/\\d+/\\d+.shtml'), callback = 'parse_item',follow = True),
)
def parse_item(self, response):
item = SunItem()
#標題
item['title'] = response.xpath('//div[contains(@class, "pagecenter p3")]//strong/text()').extract()[0]
# 編號
item['id'] = item['title'].split(' ')[-1].split(":")[-1]
# 內容
item['content'] = response.xpath('//div[@class="c1 text14_2"]/text()').extract()[0]
# 鏈接
item['url'] = response.url
yield item
第六步:編寫管道文件:SunPipeline。
import json
class SunPipeline(object):
# __init__方法是可選的,做為類的初始化方法
def __init__(self):
# 創建了一個 sun.json 文件,用來保存數據
self.filename = open("sun.json", "wb")
# process_item方法是必須寫的,用來處理item數據
def process_item(self, item, spider):
text = json.dumps(dict(item), ensure_ascii = False) + ",\\n"
# 把數據寫入到sun.json 文件中,編碼為:utf-8
self.filename.write(text.encode("utf-8"))
return item
# close_spider方法是可選的,結束時調用這個方法
def close_spider(self, spider):
self.filename.close()
第七步:修改 settings 文件。
在settings.py文件配置裡指定剛才編寫的管道文件名:SunPipeline。
設置爬蟲請求的默認頭信息。
第八步:運行爬蟲。
在 dos下切換到目錄
D:\\scrapy_project\\dg_sun\\dg_sun 下
通過命令運行爬蟲 :scrapy crawl sun
第九步:查看爬取的結果。
查看新建的sun.json 數據文件。
1.2 Scrapy 爬蟲進階案例二
Scrapy 爬蟲案例二:完善東莞陽光熱線問政平臺案例。
上面我們講解了Scrapy 爬蟲案例:東莞陽光熱線問政平臺。查看爬取後的數據,發現3個問題。
(問題一)提取的投訴內容前面有空格。
(問題二)個別投訴帖子,提取的內容不全,例如下面帖子有2段話,只是提取了第一段話:
{"id": "195592 ", "title": " 提問:南城宏遠外國語學校門口交通秩序混亂 編號:195592 ", "content": " 開學季到來,金豐路宏遠外國語學校路段每天早上又恢復塞車,此路段有宏外及陽光二小兩所學校,每天早上學生家長送孩子上學車輛十分密集,加上週邊小區居民上班高峰,極易造成塞車,更要命的是宏外路口賣花,賣水果三輪車偏偏停在路口,宏外學生家長路邊隨意停車,沒有做到即停即走,其實家長只要停車把孩子交給學校義工或保安就可以開車離開了,而很多家長都是停車然後送孩子進學校再出來開車,而這時候後面車龍已經排的很長了,有些司機加塞搶道更是加重了道路的擁堵。", "url": "http://wz.sun0769.com/html/question/201809/384482.shtml"},
分析頁面的結構:
1、內容如果有幾段話,每一段話有個
2、每段話前有一串字符:  (文本里的空字符);
通過 XPath helper 去定位內容,查看結果是 OK 的。
item['content'] = response.xpath('//div[@class="c1 text14_2"]/text()').extract()返回的是文本列表,在我們在代碼裡取得是 extract()[0],所以取得內容是第一段話。
修改爬蟲文件代碼,只取 content 內容,看爬取得到的結果是什麼。
運行的結果:
其中一條數據:{"content": [" 1.城軌D出口長期封閉導致紅珊瑚附近居民跨越馬路,造成相關大的安全隱患!", " 2.廣鐵的工作人員說領導說不準開,成本太高。但是附近那麼多居民橫跨馬路如果一旦造成人員傷亡是否廣鐵公司或者松山湖管委會負責人?", " 3.若覺得成本太高,可以開放樓梯讓乘客走下去和上來,", " 這麼多投訴之後管委會,請問下這就是為人民服務的政府嗎?", " 今天下班看到一大群人在路中間跑來跑去,出人命的時候想問下管委會是怎麼給人民交代!", " "]},
問題一和問題二處理的方案:
#獲取每個投訴的 content 內容列表
content = response.xpath('//div[@class="c1 text14_2"]/text()').extract()
#把列表轉化成字符串,並去掉前面的空格
item['content'] = "".join(content).strip()
重新運行看結果:
(問題三)很多投訴內容為空。
經過分析頁面,發現個別投訴信息上傳了圖片。
頁面元素分析:
如果投訴有圖片,內容的路徑是如下:
content = response.xpath('//div[@class="contentext"]/text()').extract()
問題三的處理方案:修改爬蟲代碼
# 內容,先使用有圖片情況下的匹配規則,如果有內容,返回所有內容的列表集合
content = response.xpath('//div[@class="contentext"]/text()').extract()
# 如果沒有內容,則返回空列表,則使用無圖片情況下的匹配規則
if len(content) == 0:
content = response.xpath('//div[@class="c1 text14_2"]/text()').extract()
item['content'] = "".join(content).strip()
else:
item['content'] = "".join(content).strip()
分析完問題,有了處理方案之後,重新完整的實現爬蟲案例。
案例步驟:
第一步:創建項目。
在 dos下切換到目錄
D:\\scrapy_project
新建一個新的爬蟲項目:scrapy startproject dg_sun2
第二步:明確需要爬取的內容字段,分析網站的結構( URL、需要爬取的字段的結構)。
【分析分頁URL地址】
從圖片中看到投訴信息列表有3192頁。
第一頁的鏈接地址:
http://wz.sun0769.com/index.php/question/questionType?type=4&page=0
第二頁的鏈接地址:
http://wz.sun0769.com/index.php/question/questionType?type=4&page=30
最後一頁的鏈接地址:
http://wz.sun0769.com/index.php/question/questionType?type=4&page=95730
通過分析我們得知,每一頁的的鏈接地址page的值遞增30,就是下一頁的地址。
【分析每一條投訴信息】
在列表裡點某條投訴信息,進入到某條投訴詳情頁。
投訴信息的編號、標題、內容如下:
查看這些字段在頁面裡的位置。
通過對頁面的分析,得出需要保存的數據字段在頁面上的位置。
#標題
title=response.xpath('//div[contains(@class, "pagecenterp3")]//strong/text()').extract()[0]
# 編號是標題裡的一部分,通過字符串切片,得到編號的內容。
id =title.split(' ')[-1].split(":")[-1]
# 內容,先使用有圖片情況下的匹配規則,如果有內容,返回所有內容的列表集合
content = response.xpath('//div[@class="contentext"]/text()').extract()
# 如果沒有內容,則返回空列表,則使用無圖片情況下的匹配規則
if len(content) == 0:
content = response.xpath('//div[@class="c1 text14_2"]/text()').extract()
item['content'] = "".join(content).strip()
else:
item['content'] = "".join(content).strip()
#鏈接就是請求返回的URL
url=response.url
第三步:編寫 items.py 文件,設置好需要保存的數據字段。
import scrapy
class SunItem(scrapy.Item):
# define the fields for your item here like:
# 標題
title = scrapy.Field()
# 編號
id = scrapy.Field()
# 內容
content = scrapy.Field()
# 鏈接
url = scrapy.Field()
第四步:創建爬蟲。
在 dos下切換到目錄
D:\\scrapy_project\\dg_sun\\dg_sun\\spiders
用命令 scrapy genspider -t crawl sun " wz.sun0769.com " 創建爬蟲。
第五步:編寫爬蟲文件。
import scrapy,sys,os
# 導入CrawlSpider類和Rule
from scrapy.spiders import CrawlSpider, Rule
# 導入鏈接規則匹配類,用來提取符合規則的連接
from scrapy.linkextractors import LinkExtractor
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(path)
from dg_sun.items import SunItem
class SunSpider(CrawlSpider):
name = 'sun'
allowed_domains = ['wz.sun0769.com']
start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=0']
# 投訴分頁鏈接的提取規則,返回的符合匹配規則的鏈接匹配對象的列表(這裡提取的是分頁的鏈接)
pagelink = LinkExtractor(allow=r'type=4&page=\\d+')
# 投訴詳情頁內容鏈接的提取規則,返回的符合匹配規則的鏈接匹配對象的列表
Details = LinkExtractor(allow=r'/html/question/\\d+/\\d+.shtml')
# 多條 Rule
rules = (
# 提取匹配,並跟進鏈接(沒有 callback 意味著 follow 默認為 True )
Rule(pagelink),
Rule(Details, callback='parse_item', follow=True),
)
# 指定的回調函數
def parse_item(self, response):
item = SunItem()
# 標題
item['title'] = response.xpath('//div[contains(@class, "pagecenter p3")]//strong/text()').extract()[0]
# 編號
item['id'] = item['title'].split(' ')[-1].split(":")[-1]
# 內容,先使用有圖片情況下的匹配規則,如果有內容,返回所有內容的列表集合
content = response.xpath('//div[@class="contentext"]/text()').extract()
# 如果沒有內容,則返回空列表,則使用無圖片情況下的匹配規則
if len(content) == 0:
content = response.xpath('//div[@class="c1 text14_2"]/text()').extract()
item['content'] = "".join(content).strip()
else:
item['content'] = "".join(content).strip()
# 鏈接
item['url'] = response.url
yield item
第六步:編寫管道文件:SunPipeline。
import json
class SunPipeline(object):
# __init__方法是可選的,做為類的初始化方法
def __init__(self):
# 創建了一個 sun.json 文件,用來保存數據
self.filename = open("sun.json", "wb")
# process_item方法是必須寫的,用來處理item數據
def process_item(self, item, spider):
text = json.dumps(dict(item), ensure_ascii = False) + ",\\n"
# 把數據寫入到sun.json 文件中,編碼為:utf-8
self.filename.write(text.encode("utf-8"))
return item
# close_spider方法是可選的,結束時調用這個方法
def close_spider(self, spider):
self.filename.close()
第七步:修改 settings 文件。
在settings.py文件配置裡指定剛才編寫的管道文件名:SunPipeline。
設置爬蟲請求的默認頭信息。
第八步:運行爬蟲。
在 dos下切換到目錄
D:\\scrapy_project\\dg_sun2\\dg_sun 下
通過命令運行爬蟲 :scrapy crawl sun
第九步:查看爬取的結果。
查看新建的sun.json 數據文件。
1.3 Scrapy 爬蟲進階案例三
Scrapy 爬蟲案例三:用 Spider 類改寫“東莞陽光熱線問政平臺”案例。
案例步驟:
第一步:創建項目。
在 dos下切換到目錄
D:\\scrapy_project
新建一個新的爬蟲項目:scrapy startproject dg_sun3
第二步:明確需要爬取的內容字段,分析網站的結構( URL、需要爬取的字段的結構)。
【分析分頁URL地址】
從圖片中看到投訴信息列表有3192頁。
第一頁的鏈接地址:
http://wz.sun0769.com/index.php/question/questionType?type=4&page=0
第二頁的鏈接地址:
http://wz.sun0769.com/index.php/question/questionType?type=4&page=30
最後一頁的鏈接地址:
http://wz.sun0769.com/index.php/question/questionType?type=4&page=95730
通過分析我們得知,每一頁的的鏈接地址page的值遞增30,就是下一頁的地址。
【每一頁帖子的鏈接集合】
# 每一頁帖子的鏈接集合
links = response.xpath('//div[@class="greyframe"]/table/a[@class="news14"]/@href').extract()
【分析每一條投訴字段信息】
在列表裡點某條投訴信息,進入到某條投訴詳情頁。
投訴信息的編號、標題、內容如下:
查看這些字段在頁面裡的位置。
通過對頁面的分析,得出需要保存的數據字段在頁面上的位置。
# 標題
title=response.xpath('//div[contains(@class, "pagecenterp3")]//strong/text()').extract()[0]
# 編號是標題裡的一部分,通過字符串切片,得到編號的內容。
id =title.split(' ')[-1].split(":")[-1]
# 內容,先使用有圖片情況下的匹配規則,如果有內容,返回所有內容的列表集合
content = response.xpath('//div[@class="contentext"]/text()').extract()
# 如果沒有內容,則返回空列表,則使用無圖片情況下的匹配規則
if len(content) == 0:
content = response.xpath('//div[@class="c1 text14_2"]/text()').extract()
item['content'] = "".join(content).strip()
else:
item['content'] = "".join(content).strip()
第三步:編寫 items.py 文件,設置好需要保存的數據字段。
import scrapy
class SunItem(scrapy.Item):
# define the fields for your item here like:
# 標題
title = scrapy.Field()
# 編號
id = scrapy.Field()
# 內容
content = scrapy.Field()
# 鏈接
url = scrapy.Field()
第四步:創建爬蟲。
在 dos下切換到目錄
D:\\scrapy_project\\dg_sun3\\dg_sun\\spiders
用命令 scrapy genspider sun " wz.sun0769.com " 創建爬蟲。
第五步:編寫爬蟲文件。
import scrapy,sys,os
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(path)
from dg_sun.items import SunItem
class SunSpider(scrapy.Spider):
name = 'sun'
allowed_domains = ['wz.sun0769.com']
url = 'http://wz.sun0769.com/index.php/question/questionType?type=4&page='
offset = 0
start_urls = [url + str(offset)]
# 第一個方法 :parse(self, response),處理(提取)每一頁鏈接。
def parse(self, response):
# 每一頁帖子的鏈接集合
links = response.xpath('//div[@class="greyframe"]/table//td/a[@class="news14"]/@href').extract()
# 迭代取出集合裡的鏈接。
for link in links:
# 提取列表裡的每個鏈接,發送請求,放到請求隊列裡,並調用回調函數 parse_item(self, response)來處理。
yield scrapy.Request(link,callback=self.parse_item)
#offset 不斷自增,直到最後一頁,在停止自增前,不斷髮送新的頁面請求,並調用自己(parse()方法)來處理。
if self.offset <= 95730:
self.offset += 30
# 發送請求,放到請求隊列裡,調用 self.parse()方法。
yield scrapy.Request(self.url+str(self.offset), callback=self.parse)
# 第二個方法 :parse_item(self, response),處理每一頁的每一個帖子。
def parse_item(self, response):
item = SunItem()
# 標題
item['title'] = response.xpath('//div[contains(@class, "pagecenter p3")]//strong/text()').extract()[0]
# 編號
item['id'] = item['title'].split(' ')[-1].split(":")[-1]
# 內容,先使用有圖片情況下的匹配規則,如果有內容,返回所有內容的列表集合
content = response.xpath('//div[@class="contentext"]/text()').extract()
# 如果沒有內容,則返回空列表,則使用無圖片情況下的匹配規則
if len(content) == 0:
content = response.xpath('//div[@class="c1 text14_2"]/text()').extract()
item['content'] = "".join(content).strip()
else:
item['content'] = "".join(content).strip()
# 鏈接
item['url'] = response.url
# item 交給管道
yield item
第六步:編寫管道文件:SunPipeline。
import json
class SunPipeline(object):
# __init__方法是可選的,做為類的初始化方法
def __init__(self):
# 創建了一個 sun3.json 文件,用來保存數據
self.filename = open("sun3.json", "wb")
# process_item方法是必須寫的,用來處理item數據
def process_item(self, item, spider):
text = json.dumps(dict(item), ensure_ascii = False) + ",\\n"
# 把數據寫入到sun3.json 文件中,編碼為:utf-8
self.filename.write(text.encode("utf-8"))
return item
# close_spider方法是可選的,結束時調用這個方法
def close_spider(self, spider):
self.filename.close()
第七步:修改 settings 文件。
在settings.py文件配置裡指定剛才編寫的管道文件名:SunPipeline。
設置爬蟲請求的默認頭信息。
第八步:運行爬蟲。
在 dos下切換到目錄
D:\\scrapy_project\\dg_sun3\\dg_sun 下
通過命令運行爬蟲 :scrapy crawl sun
首先提取列表裡的每個鏈接,發送請求,放到請求隊列裡,然後再爬取每個投訴的相關信息。
第九步:查看爬取的結果。
查看新建的 sun3.json 數據文件。
閱讀更多 聽海8 的文章