python爬蟲


查看解析html查找API



其實我們發現這就是一條json語句


去除頭部和尾部就是一條json文件,解析json文件即可

Scrapy

Scrapy 是用 Python 實現的一個為了爬取網站數據、提取結構性數據而編寫的應用框架。 Scrapy常應用在包括數據挖掘,信息處理或存儲歷史數據等一系列的程序中。 通常我們可以很簡單的通過Scrapy 框架實現一個爬蟲,抓取指定網站的內容或圖片。

1、架構圖


Scrapy Engine(引擎): 負責Spider、ItemPipeline、Downloader、Scheduler 中間的通訊,信號、數據傳遞等。
Scheduler(調度器): 它負責接受引擎發送過來的Request請求,並按照一定的方式進行整理排列,入隊,當引擎需要時,交還給引擎。
Downloader(下載器):負責下載Scrapy Engine(引擎)發送的所有Requests請求,並將其獲取到的Responses交還給Scrapy Engine(引擎),由引擎交給Spider 來處理,
Spider(爬蟲):它負責處理所有Responses,從中分析提取數據,獲取Item字段需要的數據,並將需要跟進的URL提交給引擎,再次進入Scheduler(調度器).
Item Pipeline(管道):它負責處理Spider中獲取到的Item,並進行進行后期處理(詳細分析、過濾、存儲等)的地方。
Downloader Middlewares(下載中間件):你可以當作是一個可以自定義擴展下載功能的組件。
Spider Middlewares(Spider中間件):你可以理解為是一個可以自定擴展和操作引擎和Spider中間通信的功能組件(比如進入Spider的Responses;和從 Spider出去的Requests)

2、Scrapy的運作流程

代碼寫好,程序開始運行...
1 引擎:Hi!Spider, 你要處理哪一個網站?
2 Spider:老大要我處理xxxx.com。
3 引擎:你把第一個需要處理的URL給我吧。
4 Spider:給你,第一個URL是xxxxxxx.com。
5 引擎:Hi!調度器,我這有request請求你幫我排序入隊一下。
6 調度器:好的,正在處理你等一下。
7 引擎:Hi!調度器,把你處理好的request請求給我。
8 調度器:給你,這是我處理好的request
9 引擎:Hi!下載器,你按照老大的下載中間件的設置幫我下載一下這個 request請求
10 下載器:好的!給你,這是下載好的東西。(如果失敗:sorry,這個 request下載失敗了。然后引擎告訴調度器,這個request下載失敗了,你記錄一 下,我們待會兒再下載)
11 引擎:Hi!Spider,這是下載好的東西,並且已經按照老大的下載中間件處理過了,你自己處理一下(注意!這兒responses默認是交給def parse()這個函數處理的)
12 Spider:(處理完畢數據之后對於需要跟進的URL),Hi!引擎,我這里有 兩個結果,這個是我需要跟進的URL,還有這個是我獲取到的Item數據。
13 引擎:Hi !管道 我這兒有個item你幫我處理一下!調度器!這是需要跟進 URL你幫我處理下。然后從第四步開始循環,直到獲取完老大需要全部信息。
14 管道調度器:好的,現在就做!
注意!只有當調度器中不存在任何request了,整個程序才會停止,(也就是說,對於下載 失敗的
URL,Scrapy也會重新下載。)

3、制作Scrapy爬蟲步驟

1、安裝Scrapy框架


2、使用startproject命令,快速構建scrapy項目


3、爬取百度首頁

import scrapy

class BaiduDemo(scrapy.Spider):
    # 爬蟲的名稱 用於啟動爬蟲
    name = 'BaiduDemo'
    # 設置允許爬取的域名
    allowed_domains = ['baidu.com']
    # 啟動的url
    start_urls = ['http://www.baidu.com']

    # 解析函數
    def parse(self, response):
        print(response.text)


4、爬取京東商品評論導入數據庫

爬取數據




代碼

import scrapy

class JDCommentsSpider(scrapy.Spider):
    name = 'JDCommentsSpider'
    allowed_domains = ['jd.com']

    # 設定請求頭 偽裝成瀏覽器
    headers = {
        "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"
    }

    # start_urls = ['https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100014352539&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1']
    # 手動的發起請求
    def start_requests(self):
        url = 'https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100014352539&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1'
        # header 請求頭
        # callback 回調函數 :設置由哪個函數去解析response
        yield scrapy.Request(url=url, headers=self.headers, callback=self.parseComment)
        
    def parseComment(self, response):
        print(response.text)

解析數據

解析思路((fetchJSON_comment98()({.*})()😉),通過使用正則表達式獲取中間的json格式內容

import re
import json

# (fetchJSON_comment98\()({.*})(\);)
json_str1 = r'fetchJSON_comment98({"jwotestProduct":null,"score":0,"comments":[{"id":16704617220,"guid":"573c70c3703d3ee1d6745412533c59bf","content":"外形外觀:直角邊框經典設計,手感非常好。不銹鋼邊框很有質感\n屏幕音效:iPhone屏"}]});'
groups = re.match(r"(fetchJSON_comment98\()(.*)(\);)", json_str1)
# 返回正則表達式匹配到的整行數據
print(groups.group(0))
print(groups.group(1))
print(groups.group(2))
print(groups.group(3))

# jsonObj = json.loads(groups.group(2))
# print(jsonObj)
# print(type(jsonObj))

str1 = r'abc\tefg'
print(str1)

從爬取數據中獲取json

import scrapy
import re
import json

class JDCommentsSpider(scrapy.Spider):
    name = 'JDCommentsSpider'
    allowed_domains = ['jd.com']

    # 設定請求頭 偽裝成瀏覽器
    headers = {
        "user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"
    }

    # start_urls = ['https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100014352539&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1']
    # 手動的發起請求
    def start_requests(self):
        url = 'https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100014352539&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1'
        # header 請求頭
        # callback 回調函數 :設置由哪個函數去解析response
        yield scrapy.Request(url=url, headers=self.headers, callback=self.parseComment)

    def parseComment(self, response):
        # print(response.text)
        json_str = re.match(r"(fetchJSON_comment98\()(.*)(\);)", response.text).group(2)
        print(json_str)
        commentDict = json.loads(json_str)
        print(commentDict)

#明確爬取目標的格式
class CommentItem(scrapy.Item):
    id = scrapy.Field()
    content = scrapy.Field()
    creationTime = scrapy.Field()
    score = scrapy.Field()
    nickname = scrapy.Field()

import scrapy
import re
import json
from ..items import CommentItem

class JDCommentsSpider(scrapy.Spider):
    name = 'JDCommentsSpider'
    allowed_domains = ['jd.com']

    # 設定請求頭 偽裝成瀏覽器
    headers = {
        'Accept': '*/*',
        'Accept-Encoding': 'gzip, deflate, br',
        'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
        'Connection': 'keep-alive',
        'Cookie': 'shshshfpb=f3W7aXOimfXUdxcnPVcp8lg%3D%3D; shshshfpa=dd3e618e-7824-e463-e953-735fb2491a30-1572581065; __jdu=15945342777701271159704; user-key=0f674e76-283e-4314-878d-e20485b0bdf9; __jdv=76161171|direct|-|none|-|1639622083019; areaId=14; PCSYCityID=CN_340000_340100_0; ipLoc-djd=14-1116-3431-57939; jwotest_product=99; __jda=122270672.15945342777701271159704.1594534278.1639635327.1639703524.27; __jdc=122270672; token=d580f8297475335873c53a0ca9a442ab,2,910946; __tk=WkaFSLmLVcaCiAeFTLfKVkuCVUvJWceAiDl3iLl2Tce,2,910946; shshshfp=e39a2aab2d64e3d87934802270acb44f; ip_cityCode=1116; shshshsID=92d1c2eec0e0061568b20502af8aa0fb_4_1639703565703; __jdb=122270672.5.15945342777701271159704|27.1639703524; JSESSIONID=4C9F7710F36CC25E02E63C1F6D8706AD.s1; 3AB9D23F7A4B3C9B=PFFHAXCONWJKWHSOLBIBQWHWZCSNLF65GANEXSUBWYJQK3UFYOGIH3BMJJ56DKIL2GTESYLRTXH2CLWABB7Z37WOSY',
        'Host': 'club.jd.com',
        'Referer': 'https://item.jd.com/',
        'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Windows"',
        'Sec-Fetch-Dest': 'script',
        'Sec-Fetch-Mode': 'no-cors',
        'Sec-Fetch-Site': 'same-site',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
    }

    # start_urls = ['https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100014352539&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1']
    # 手動的發起請求
    def start_requests(self):
        url = 'https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100014352539&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1'
        # header 請求頭
        # callback 回調函數 :設置由哪個函數去解析response
        for i in range(80):
            url = url.format(i)
            # headers 請求頭
            # callback 回調函數:設置由哪個函數去解析response
            yield scrapy.Request(url=url, headers=self.headers, callback=self.parseComment)

    def parseComment(self, response):
        # print(response.text)
        json_str = re.match(r"(fetchJSON_comment98\()(.*)(\);)", response.text).group(2)
        print(json_str)
        commentDict = json.loads(json_str)
        # print(commentDict)
        #解析數據
        comments = commentDict.get('comments',None)
        if comments is not None:
            for comment in comments:
                #從response中解析數據並構建Item對象
                commentItem = CommentItem()
                commentItem['id'] = comment['id']
                commentItem['content'] = comment['content']
                commentItem['creationTime'] = comment['creationTime']
                commentItem['score'] = comment['score']
                commentItem['nickname'] = comment['nickname']
                #將遍歷好的Item對象發送給piepline做后續處理
                yield commentItem

寫入到MySQL

在MySQL新建數據庫和字段

在pipelines.py寫代碼
import pymysql
class ScrapydemoPipeline:
    #初始化連接MySQL數據庫
    def open_spider(self,spider):
        self.conn = pymysql.connect(user='root',passwd='123456',host='master',port=3306,db='spiders')

    def process_item(self, item, spider):
        #寫入mysql
        id = item['id']
        content = item['content']
        creationTime = item['creationTime']
        score = item['score']
        nickname = item['nickname']
        #創建游標
        try:
            print("*************")
            with self.conn.cursor() as cursor:
                cursor.execute('insert into comments values(%s,%s,%s,%s,%s)',(id,nickname,score,creationTime,content))
        except Exception as e:
            print(e)
            #發生異常進行回滾
            self.conn.rollback()
        else:
            #沒有異常就提交寫入的數據
            self.conn.commit()
        return item
    #關閉數據庫
    def close_spider(self,spider):
        self.conn.close()


爬取多頁評論寫入MySQL

先清空表中數據
設置停歇訪問,以免被攔截

  # start_urls = ['https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100014352539&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1']
    # 手動的發起請求
    def start_requests(self):
        url_format = 'https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100014352539&score=0&sortType=5&page={}&pageSize=10&isShadowSku=0&fold=1'
        # header 請求頭
        # callback 回調函數 :設置由哪個函數去解析response
        for i in range(80):
            url = url_format.format(i)
            # headers 請求頭
            print(url_format)
            # callback 回調函數:設置由哪個函數去解析response
            yield scrapy.Request(url=url, headers=self.headers, callback=self.parseComment)



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM