Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Pro : Excel 2010)
Webページを開かせたい2
投稿日時: 19/08/25 08:37:49
投稿者: andoandoando

お世話になっております。
先ほど、EXCELのセルに書いてある複数URLを選択し、マクロでそれらを開く、についてはご回答いただきできるようになりました。
 
次に下記のようにyahooで検索を掛けたいです。
(前回はURLがセルに書いてありました。今回はキーワードのみが書いてあり、いろんな検索サイトで検索掛けたいです)
 
このままですと424のobject reqest エラーが出ます。
set adr= とすると、object reqest エラーが出ます。(エラーNoがでません)
(setをはずして)Variantをrange にしてもエラー91のObject or With block varianble not set とでます。
set adr = で Variantをrange にしてもset adr = でtype mismatch となります。
 
やりたいことをまとめると
@フィルターが掛かっているセルから、複数の見えてるセルのみを使い
A検索サイト(今回はyahoo)で検索させたページを表示させたい
です。
 
お手数おかけいたします。
なにかわかればお教えいただきたくよろしくお願いいたします。
 
 
 Dim adr As Variant
  
     adr = "https://search.yahoo.co.jp/search?p="
  If TypeName(Selection) <> "Range" Then Exit Sub
 
For Each rng In Selection.SpecialCells(xlCellTypeVisible)
       rng = adr & rng
        rng.Hyperlinks.Add anchor:=rng, Address:=rng.Value
        rng.Hyperlinks(1).Follow NewWindow:=False, AddHistory:=True
    Next rng

回答
投稿日時: 19/08/25 09:15:31
投稿者: simple

Option Explicit
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub test()
    Dim url As String
    Dim rng As Range

    url = "https://search.yahoo.co.jp/search?p="
    If TypeName(Selection) <> "Range" Then Exit Sub

    For Each rng In Selection.SpecialCells(xlCellTypeVisible)
        rng.Hyperlinks.Add anchor:=rng, Address:=url & encodeUrlUtf8(rng.Value)
        Sleep 1000  '1秒処理を待つ
        rng.Hyperlinks(1).Follow NewWindow:=False, AddHistory:=True
    Next
End Sub
Public Function encodeUrlUtf8(ByRef strSource As String) As String
    Dim objSC As Object

    Set objSC = CreateObject("ScriptControl")
    objSC.Language = "Jscript"
    encodeUrlUtf8 = objSC.CodeObject.encodeURIComponent(strSource)
    Set objSC = Nothing
End Function

標準モジュールに置いて実行してください。
 
urlエンコードの箇所は、
https://qiita.com/pocket8137/items/996392e35d4426c4b4d6
から引用させていただきました。

投稿日時: 19/08/26 07:11:22
投稿者: andoandoando

simple 様
 
ご回答ありがとうございます。
動きました!
 
私の書いたものでは何が悪かったのかが不明なのですが、お教えいただけませんでしょうか?
 
というのは今まで動いていたのですがなぜか動かなくなってしまい、前回教えていただいた「複数URLを開く」コードを基本にして置き換えたのが前述でした。
 
使っている変数 adrとrngが型が違うのだなということはわかります。
が以前はadr&rngでURLを作ってwebページを開くことができていたので、同じようにやってできないのが不思議だなと。
 
セルに入っているキーワードは半角英数字を+でつなげたもの(例:abc+def+xyz)にしていますので普通の文字でしたらURL化できていると思います。
 
以上ご教授いただけますと幸いです。

回答
投稿日時: 19/08/26 08:13:47
投稿者: simple

ステップ実行してみてください。
その結果を教えて下さい。
 
それと、Sub ○○() から End Subまで省略せずに載せた方が
よいと思います。

投稿日時: 19/08/26 21:26:25
投稿者: andoandoando

simple 様
 
ご返信ありがとうございます。
遅くなりました。
 
実行してみました。(使っているものは少し長いので、下記のシンプルな必要な部位だけにて)
 
Sub text4()
 Dim adr As Variant
   
     adr = "https://search.yahoo.co.jp/search?p="
  If TypeName(Selection) <> "Range" Then Exit Sub
  
For Each rng In Selection.SpecialCells(xlCellTypeVisible)
       rng = adr & rng
        rng.Hyperlinks.Add anchor:=rng, Address:=rng.Value   '**************
        rng.Hyperlinks(1).Follow NewWindow:=False, AddHistory:=True
    Next rng
End Sub
 
 
エラーがでます。
前回同様424のobject reqest エラーが出ました。
場所は
 rng.Hyperlinks.Add anchor:=rng, Address:=rng.Value   '**************
のところで黄色くハイライトされました。
 
また、選んだセルにはjhjcq510と書いてありますが、止まったところの上の行のrngには
rng = "https://search.yahoo.co.jp/search?p=出品名"
( rng = adr & rngの先頭 rngにカーソル合わせて出てきた表示内容)
 
となっていました。
本来は rng = "https://search.yahoo.co.jp/search?p=jhjcq510"となってほしい。
 
ちなみに出品名というのはA1セルに入っている言葉です。
 
解決はできていますので、今後の勉強のためにお時間取らずにわかるのでしたらお教えいただければ嬉しいです。
 
以上よろしくお願いいたします。

回答
投稿日時: 19/08/26 23:14:32
投稿者: simple

(Q1) rngという変数が宣言なしに使われていますが、それはなぜなんですか?
    Option Explicit を一行目に書いていますか?
(Q2) rngは何型であるべきだと思いますか?

回答
投稿日時: 19/08/27 09:04:12
投稿者: simple

For Each rng In Selection.SpecialCells(xlCellTypeVisible)
は、
(1)rngを Rangeオブジェクトと宣言していれば、
Selection.SpecialCells(xlCellTypeVisible)というセル範囲(Rangeオブジェクト)を
構成する、それぞれのセル(Range)について、処理を行う、と言う意味になる。

(2)しかし、rngの型が指定されていないと(Variantと見なされ)、
Selection.SpecialCells(xlCellTypeVisible)の値からなる配列の
各要素(文字列であったり、数値であったりする。この例では文字列)について、
処理を行う、と意味になる。
( Selection.SpecialCells(xlCellTypeVisible).Value と補って解釈される)
 
(2)の場合は、
ステップ実行するとわかるが、rng は 文字列(の値を持つVariant型)だから、
Address:=rng.Value
などということは無意味です。文字列はオブジェクトじゃないから、
rng.Value などといわれても、はて??! 、ということになる。
 
ちなみに
>424のobject reqest エラーが出ます。
そんなエラーはありません。object required でしょう。
つまり、「オブジェクトが必要」ということ。
 
オブジェクトが想定する処理(プロパティの取得や、メソッドの実行)を
指示しているけど、そいつはオブジェクトなんかじゃないぜ、
オブジェクトが必要だぞ、と言っている。
--------------------------
(3)
では、型指定を省略したとき、なぜ(1)と自動的に解釈されずに、(2)と解釈されてしまうか、
それは正確なことは知りませんが、objectのほうが構造が複雑であることから、
明確にobjectとして指定しない限り、(2)のような簡易なものと解釈することになっているのでしょう。
 
そのような文法上の細部よりも、まずは、
・Option Explicit を明記し(自動で設定するオプションもあります)
・きちんと型を指定すること

を守って下さい。
-------------------------
追加:
> set adr= とすると、object reqest エラーが出ます。(エラーNoがでません)
文字列はオブジェクトではありません。したがって、それは無効です。
まずは、そうした基本的なことを了解することが先決でしょう。
 
そして rngはRangeオブジェクトであると認識していれば、
rng = adr & rng
などという書き方にはならないはずです。
普通は
rng.Value = adr & rng.Value
などと書くはずです。そのほうが意図が明確になります。
 
また、そうすれば、
何度も処理すれば、その都度、urlが追加されて困ったことになる、
といったことにも気づくはずです。

回答
投稿日時: 19/08/27 12:53:45
投稿者: 半平太

>(2)しかし、rngの型が指定されていないと(Variantと見なされ)、
>Selection.SpecialCells(xlCellTypeVisible)の値からなる配列の
>各要素(文字列であったり、数値であったりする。この例では文字列)について、
>処理を行う、と意味になる。
>( Selection.SpecialCells(xlCellTypeVisible).Value と補って解釈される)
 
そんなことはありません。
 
Vaiant型はオブジェクト型にもなれます。(別にその使い方を推奨する心算りはありませんが。)
 
これが間違い。
 ↓
>rng = adr & rng
 
  rng.Value = adr & rng
 
とすべきだったのだが、左辺のValueプロパティを省略したため、
右辺の合成文字列を代入されたとき、「内部形式文字列」のありきたりのVariant型に変えられてしまった。

回答
投稿日時: 19/08/27 15:14:29
投稿者: simple

半平太さん、そのとおりですね。
ありがとうございます。
 
多重ディスパッチ可能な言語にこのところ入れ込んでいたので、
勝手な推測をしてしまいましたww
 
明示的に .Valueをつけないとダメな典型的なケースでしたね。
そういう議論があったのを想い出しました。
 
いずれにしても、きちんと変数の型を宣言するようにしてください。> 質問者さん

投稿日時: 19/08/27 23:08:28
投稿者: andoandoando

ご返信遅くなり申し訳ありません。
 
自分での調べとその後の書き込みいただいたことでなんとなくですが理解できました。
ありがとうございます。
 
自分はrngは配列だと思っていましたので
Dim rng() as Variant
といった宣言が足りないのかと思ったのですが違いましたね。
 
今まで型の宣言しなくてもなんとなく動いていたので、指定しなくなっていましたが間違いに気づきやすくなることがわかりました。
これから宣言するようにいたします。
 
また、動くようになりました!とご報告したご提示いただいたプログラムですが、
フィルター掛けたものでセルを1づだけ選んだ場合、誤動作します。
 
AAAと入っているとしても、その内容には関係なくA1、B1、C1・・・・と横にセルを選んだように動きます。
 
フィルターをはずしてセル1つ選択、では正常動作します。
 
こちらについてもご教授いただけますと助かります。
以上よろしくお願いいたします。

回答
投稿日時: 19/08/28 19:17:16
投稿者: simple

ご教授といわれてもなにですが、難しく考えることはないのでは?
Selectionが1つだけのときに異常がおきるのであれば、
Selection.Countで判定して、
1のときだけ、Selctionに対して直接、処理をすればよいのではないでしょうか。
ご自分でトライしてみて下さい。

投稿日時: 19/08/28 21:37:20
投稿者: andoandoando

simple 様
 
ありがとうございます。
できるようになりました。
 
1つのときは別処理してとのことで、今までの実力で行きつきましたがそのアドバイス無かったら1つのときも同じ内容で処理するにはどうしたら良いかという方向に進んでいたと思います。
 
これで解決しました。
勉強になりました。
ありがとうございました。